Skip to content

MenuItem

MenuItem (from scenerystack/sun) is a single row used by PhET's built-in PhetMenu (the "hamburger" options menu every published sim has) — a label, a hover highlight, an optional checkmark, and a FireListener that closes the menu and runs a callback. It's documented here because it's exported from scenerystack/sun and usable on its own if you're building a custom popup menu that should look and behave consistently with PhET's, not because most sim code constructs PhetMenu items directly.

ts
import { MenuItem } from 'scenerystack/sun';
import { Property, StringProperty } from 'scenerystack/axon';

const closeMyMenu = () => { myMenuPopup.visible = false; };

const soundEnabledProperty = new Property<boolean>( true );
const labelStringProperty = new StringProperty( 'Enable Sound' );

const soundMenuItem = new MenuItem(
  event => closeMyMenu(),               // closeCallback
  labelStringProperty,                  // labelStringProperty
  event => {                            // callback, run after closeCallback
    soundEnabledProperty.value = !soundEnabledProperty.value;
  },
  true,                                  // present
  false,                                 // shouldBeHiddenWhenLinksAreNotAllowed
  {
    checkedProperty: soundEnabledProperty
  }
);

The constructor is positional and PhET-menu-specific: closeCallback runs first (typically hiding the menu popup), then callback runs the item's actual action. present lets a menu build a consistent, fixed set of MenuItems across runtimes while hiding ones that don't apply in a given context (rather than conditionally omitting them, which would change PhET-iO's API shape). shouldBeHiddenWhenLinksAreNotAllowed ties the item's visibleProperty to scenerystack/scenery's allowLinksProperty, for items whose action is a link that some embedding contexts must suppress.

Options

OptionEffect
separatorBeforeDraws a horizontal rule between this item and the previous one
checkedPropertyIf provided, shows/hides a checkmark to the left of the label based on this boolean Property
textFillFill for the label Text (default 'black')

MenuItem mixes in WidthSizable, so its highlight rectangle stretches to fill whatever localPreferredWidth a parent layout container assigns it — every item in a menu ends up the same width even though their labels differ.

Read as a Voicing-enabled Node for accessibility, not a bespoke widget

MenuItem extends WidthSizable( Voicing( Node ) ), using the exact same Voicing mixin pattern as other interactive sun/scenery components — its voicingNameResponse is kept in sync with the label string automatically, so you don't need to set it by hand if you reuse MenuItem in your own popup.