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.