Loading Developer Playground

Loading ...

Skip to main content
ARIA ATTRIBUTEWidget Attributes

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.

Value Type
number
Common Use
Current Value
Used With
valuemin, valuemax

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

5

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

Related Attributes

Specifications & Resources