APG Patterns
ๆ—ฅๆœฌ่ชž
ๆ—ฅๆœฌ่ชž
๐Ÿ“

Communicating Value and Limits for Range Widgets

ARIA defines roles for four types of range widgets: scrollbar, slider, spinbutton, and meter.

This practice is documented in detail at Communicating Value and Limits for Range Widgets - WAI-ARIA APG . Below we provide additional context specific to our pattern implementations.

Overview

Range widgets allow users to set or view a value within a defined range. ARIA defines roles for four types: slider, spinbutton, scrollbar, and meter. Each requires specific properties to communicate the current value and its limits to assistive technology.

Range Widget Types

RolePurposeUser Interaction
sliderSelect a value from a rangeArrow keys, drag
spinbuttonEnter/adjust a numeric valueArrow keys, type
scrollbarControl scroll positionDrag, arrow keys
meterDisplay a gauge value (read-only)None (display only)

Required ARIA Properties

For All Range Widgets

<div
  role="slider"
  aria-valuenow="50"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-label="Volume"
></div>
PropertyRequiredDescription
aria-valuenowYesCurrent value
aria-valueminYes*Minimum value (*implicit 0 for meter)
aria-valuemaxYes*Maximum value (*implicit 100 for meter)
aria-valuetextNoHuman-readable value text

aria-valuetext for Non-numeric Values

When the value isnโ€™t meaningful as a number:

<!-- Time slider -->
<div
  role="slider"
  aria-valuenow="120"
  aria-valuemin="0"
  aria-valuemax="480"
  aria-valuetext="2:00 PM"
  aria-label="Meeting start time"
></div>

<!-- Priority slider -->
<div
  role="slider"
  aria-valuenow="2"
  aria-valuemin="1"
  aria-valuemax="5"
  aria-valuetext="Medium priority"
></div>

Native HTML Alternatives

Consider native HTML elements first:

<!-- Native range input -->
<label for="volume">Volume</label>
<input type="range" id="volume" min="0" max="100" value="50" />

<!-- Native number input (spinbutton semantics) -->
<label for="quantity">Quantity</label>
<input type="number" id="quantity" min="1" max="99" value="1" />

<!-- Native meter -->
<label for="disk-usage">Disk usage</label>
<meter id="disk-usage" min="0" max="100" low="33" high="66" optimum="20" value="75">75%</meter>

<!-- Native progress -->
<label for="upload">Upload progress</label>
<progress id="upload" max="100" value="70">70%</progress>

Implementation Tips

Multi-thumb Sliders

For sliders with multiple thumbs (e.g., price range):

<div role="group" aria-label="Price range">
  <div
    role="slider"
    aria-label="Minimum price"
    aria-valuenow="20"
    aria-valuemin="0"
    aria-valuemax="100"
  ></div>
  <div
    role="slider"
    aria-label="Maximum price"
    aria-valuenow="80"
    aria-valuemin="0"
    aria-valuemax="100"
  ></div>
</div>

Orientation

Specify orientation for vertical sliders:

<div
  role="slider"
  aria-orientation="vertical"
  aria-valuenow="50"
  aria-valuemin="0"
  aria-valuemax="100"
></div>

Read-only Meters

Meters are inherently read-only. Use meter role for display-only gauges:

<div
  role="meter"
  aria-valuenow="75"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-label="Battery level"
>
  75%
</div>

Common Pitfalls

Missing valuetext for Complex Values

<!-- Bad: Screen reader announces "50" for a time -->
<div role="slider" aria-valuenow="50" aria-valuemin="0" aria-valuemax="480" aria-label="Time"></div>

<!-- Good: Screen reader announces "8:30 AM" -->
<div
  role="slider"
  aria-valuenow="50"
  aria-valuemin="0"
  aria-valuemax="480"
  aria-valuetext="8:30 AM"
  aria-label="Time"
></div>

Inconsistent Min/Max/Now

<!-- Bad: valuenow outside range -->
<div role="slider" aria-valuenow="150" aria-valuemin="0" aria-valuemax="100"></div>

<!-- Good: valuenow within range -->
<div role="slider" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>

Using Slider for Read-only Display

<!-- Bad: Slider for display-only value -->
<div role="slider" aria-valuenow="75" aria-readonly="true"></div>

<!-- Good: Meter for display-only gauge -->
<div role="meter" aria-valuenow="75"></div>

Resources