Skip to content

AccessibleNumberSpinner

AccessibleNumberSpinner (from scenerystack/sun) is a trait — like AccessibleSlider, a function from a Node subclass to a new class with behavior mixed in, not a Node you instantiate directly. NumberSpinner is defined as class NumberSpinner extends AccessibleNumberSpinner( Node, 0 ); reach for it yourself only when building a custom spinner-like component that needs the same keyboard repeat-on-hold behavior NumberSpinner gets for free.

ts
import { AccessibleNumberSpinner } from 'scenerystack/sun';
import { Node } from 'scenerystack/scenery';
import { NumberProperty, Property } from 'scenerystack/axon';
import { Range } from 'scenerystack/dot';

class MyCustomSpinnerNode extends AccessibleNumberSpinner( Node, 0 ) {
  public constructor( valueProperty: NumberProperty, rangeProperty: Property<Range> ) {
    super( {
      valueProperty: valueProperty,
      enabledRangeProperty: rangeProperty,
      keyboardStep: 1,
      pageKeyboardStep: 5
    } );
    // ...add your own increment/decrement visuals here
  }
}

AccessibleNumberSpinner( Type, optionsArgPosition ) shares its optionsArgPosition convention with AccessibleSlider. It mixes in the same underlying AccessibleValueHandler as AccessibleSlider (so keyboardStep/shiftKeyboardStep/pageKeyboardStep/enabledRangeProperty all mean the same thing there — see AccessibleSlider), but layers spinner-specific behavior on top: a CallbackTimer-driven press-and-hold repeat (arrow keys fire once immediately, then repeat), and defaults tuned for a spinner rather than a slider — ariaOrientation: Orientation.VERTICAL and an accessibleRoleDescription announcing it as a "number spinner" (PhET's own custom ARIA role description, since native input[type=range] semantics don't quite fit; spinners use role="range" under the hood rather than number-input semantics, deliberately excluding numeric-key entry).

Behavior it adds beyond AccessibleValueHandler

InteractionEffect
Arrow keys, single pressChange the value once by keyboardStep (or shiftKeyboardStep with Shift held)
Arrow keys, held downAfter pdomTimerDelay, repeats the change every pdomTimerInterval until released
Page Up / Page Down, Home / EndSame as AccessibleSlider — larger step / jump to range extremes

Options

OptionDefaultEffect
pdomTimerDelay400 (ms)Delay before a held key starts auto-repeating
pdomTimerInterval100 (ms)Interval between repeats once auto-repeat has started
accessibleRoleDescription'number spinner' string (translated)Overridable ARIA role description announced to screen readers

Members worth knowing

MemberMeaning
pdomIncrementDownEmitter / pdomDecrementDownEmitterTEmitter<[boolean]>s that fire on keyboard-driven increment/decrement key-down and key-up — NumberSpinner uses these to style its arrow buttons as "pressed" during keyboard interaction, matching the visual feedback of a mouse press

You're almost always consuming this indirectly

As with AccessibleSlider, simulation code essentially never invokes this trait directly — it's documented so NumberSpinner's keyboard-step-family options and press-and-hold behavior have a page explaining exactly where they come from.