aria-valuenow
Defines the current value for a range widget. This is the value between aria-valuemin and aria-valuemax that represents the current position or state of the widget.
Overview
The aria-valuenow attribute defines the current value of a range widget. It must be a number between aria-valuemin and aria-valuemax.
This attribute must be updated dynamically as the user interacts with the widget. Screen readers announce value changes, helping users understand the current state.
Required Attribute
For determinate range widgets (slider, progressbar with known progress, meter), aria-valuenow is required along with aria-valuemin and aria-valuemax.
Live Demo: Spinbutton
Current ARIA attributes:
aria-valuemin="1" aria-valuemax="99" aria-valuenow="5"Screen reader: "Quantity, spin button, 5". When changed: announces new value. Use arrow keys to adjust.
Code Examples
Basic Usage
<!-- aria-valuenow indicates current value -->
<!-- Slider showing current value -->
<div
role="slider"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="65"
aria-label="Volume"
tabindex="0"
>
65%
</div>
<!-- Screen reader: "Volume, slider, 65" -->
<!-- Progress bar current state -->
<div
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="75"
aria-label="Upload progress"
>
75%
</div>
<!-- Spinbutton with current quantity -->
<div
role="spinbutton"
aria-valuemin="1"
aria-valuemax="99"
aria-valuenow="5"
aria-label="Quantity"
tabindex="0"
>
5
</div>Dynamic Updates
<!-- Dynamic value updates -->
<!-- JavaScript to update aria-valuenow -->
<div
id="download-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
aria-label="Download progress"
>
0%
</div>
<script>
function updateProgress(percentage) {
const progressBar = document.getElementById('download-progress');
progressBar.setAttribute('aria-valuenow', percentage);
progressBar.textContent = percentage + '%';
// Screen reader will announce changes
// if aria-live="polite" is also set
}
// Simulate download progress
let progress = 0;
const interval = setInterval(() => {
progress += 10;
updateProgress(progress);
if (progress >= 100) {
clearInterval(interval);
}
}, 500);
</script>Spinbutton Control
<!-- Spinbutton with value controls -->
<div class="spinbutton-container">
<label id="qty-label">Quantity</label>
<div class="spinbutton-wrapper">
<button
onclick="decreaseValue()"
aria-label="Decrease quantity"
>
−
</button>
<div
id="qty-spinbutton"
role="spinbutton"
aria-labelledby="qty-label"
aria-valuemin="1"
aria-valuemax="99"
aria-valuenow="5"
tabindex="0"
onkeydown="handleSpinbuttonKey(event)"
>
5
</div>
<button
onclick="increaseValue()"
aria-label="Increase quantity"
>
+
</button>
</div>
</div>
<script>
function updateSpinbutton(newValue) {
const spinbutton = document.getElementById('qty-spinbutton');
const min = parseInt(spinbutton.getAttribute('aria-valuemin'));
const max = parseInt(spinbutton.getAttribute('aria-valuemax'));
// Clamp value to valid range
newValue = Math.max(min, Math.min(max, newValue));
spinbutton.setAttribute('aria-valuenow', newValue);
spinbutton.textContent = newValue;
}
function increaseValue() {
const current = parseInt(
document.getElementById('qty-spinbutton')
.getAttribute('aria-valuenow')
);
updateSpinbutton(current + 1);
}
function decreaseValue() {
const current = parseInt(
document.getElementById('qty-spinbutton')
.getAttribute('aria-valuenow')
);
updateSpinbutton(current - 1);
}
function handleSpinbuttonKey(event) {
const current = parseInt(event.target.getAttribute('aria-valuenow'));
switch(event.key) {
case 'ArrowUp':
updateSpinbutton(current + 1);
event.preventDefault();
break;
case 'ArrowDown':
updateSpinbutton(current - 1);
event.preventDefault();
break;
case 'Home':
updateSpinbutton(parseInt(event.target.getAttribute('aria-valuemin')));
event.preventDefault();
break;
case 'End':
updateSpinbutton(parseInt(event.target.getAttribute('aria-valuemax')));
event.preventDefault();
break;
}
}
</script>React Components
// React components with aria-valuenow
import { useState, useCallback } from 'react';
// Custom Spinbutton Component
function Spinbutton({
min = 0,
max = 100,
value,
onChange,
label,
step = 1
}) {
const handleKeyDown = useCallback((e) => {
let newValue = value;
switch (e.key) {
case 'ArrowUp':
newValue = Math.min(value + step, max);
break;
case 'ArrowDown':
newValue = Math.max(value - step, min);
break;
case 'Home':
newValue = min;
break;
case 'End':
newValue = max;
break;
case 'PageUp':
newValue = Math.min(value + step * 10, max);
break;
case 'PageDown':
newValue = Math.max(value - step * 10, min);
break;
default:
return;
}
e.preventDefault();
onChange(newValue);
}, [value, min, max, step, onChange]);
return (
<div className="spinbutton-container">
<label id="spin-label">{label}</label>
<div className="spinbutton-controls">
<button
onClick={() => onChange(Math.max(value - step, min))}
aria-label="Decrease"
disabled={value <= min}
>
−
</button>
<div
role="spinbutton"
aria-labelledby="spin-label"
aria-valuemin={min}
aria-valuemax={max}
aria-valuenow={value}
tabIndex={0}
onKeyDown={handleKeyDown}
className="spinbutton-value"
>
{value}
</div>
<button
onClick={() => onChange(Math.min(value + step, max))}
aria-label="Increase"
disabled={value >= max}
>
+
</button>
</div>
</div>
);
}
// Progress with Live Updates
function ProgressBar({ value, max = 100, label }) {
const percentage = Math.round((value / max) * 100);
return (
<div className="progress-container">
<div className="progress-header">
<span>{label}</span>
<span>{percentage}%</span>
</div>
<div
role="progressbar"
aria-valuemin={0}
aria-valuemax={max}
aria-valuenow={value}
aria-label={label}
className="progress-bar"
>
<div
className="progress-fill"
style={{ width: `${percentage}%` }}
/>
</div>
</div>
);
}
// Usage
function ShoppingCart() {
const [quantity, setQuantity] = useState(1);
const [downloadProgress, setDownloadProgress] = useState(0);
return (
<>
<Spinbutton
label="Quantity"
min={1}
max={99}
value={quantity}
onChange={setQuantity}
/>
<ProgressBar
label="Downloading..."
value={downloadProgress}
max={100}
/>
</>
);
}Best Practices
Always keep aria-valuenow between aria-valuemin and aria-valuemax
Update aria-valuenow immediately when the value changes
Consider using aria-valuetext for human-readable descriptions
Implement keyboard support (Arrow keys, Home, End, Page Up/Down)
Don't set aria-valuenow outside the min/max range
Don't forget to update the visual display along with aria-valuenow
Don't use on native HTML range/progress elements

