CycleButton

A discrete interaction control that cycles through a set of options with support for custom visual content and multiple operation modes.

The CycleButton component provides a discrete interaction control that cycles through a set of options. It shares the same layout, parameter model, interaction, and accessibility as other vector components; see the Vector introduction.

  • Multiple visual variants: abstract, simplest, plainCap, iconCap
  • Four modes of operation: Ad-hoc (children), strict (parameter), hybrid, and options prop
  • Full theming support: color, roundness, thickness customization

Important: This control supports discrete interaction only (click to cycle, keyboard to step). It does not support continuous interaction (drag/wheel).

Props

NameTypeDefaultRequiredDescription
valuestring | numberNoCurrent value of the control (Controlled mode)
defaultValuestring | numberNoDefault value of the component (Uncontrolled mode)
onChange(event: AudioControlEvent<string | number>) => voidNoHandler for value changes
labelstringNoLabel displayed below the component
optionsDiscreteOption[]NoOption definitions for the parameter model (Ad-Hoc mode). Defines the parameter structure (value, label, midiValue). Does NOT provide visual content - use children (OptionView components) for that.
childrenReact.ReactNodeNoChild elements (OptionView components) for visual content mapping. Provides ReactNodes for rendering (icons, text, custom components). Does NOT define the parameter model - use options prop or parameter prop for that.
renderOption(option: { value: string | number; label: string }) => React.ReactNodeNoCustom renderer for options (used when parameter is provided but no children map exists)
thicknessnumber0.4NoThickness of the stroke (normalized 0.0-1.0, maps to 1-20). Used by rotary variant.
opennessnumber90NoOpenness of the ring in degrees (0-360º; 0º closed, 90º 3/4 open, 180º half-circle)
rotationnumber0NoOptional rotation angle offset in degrees
colorstringNoComponent primary color - any valid CSS color value
roundnessnumberNoRoundness for component corners (normalized 0.0-1.0)
adaptiveSizebooleanfalseNoWhether the component stretches to fill its container
size"xsmall" | "small" | "normal" | "large" | "xlarge"normalNoSize of the component
displayMode"scaleToFit" | "fill"scaleToFitNoLayout mode for the control
labelMode"none" | "hidden" | "visible"visibleNoVisibility of the label row
labelPosition"above" | "below"belowNoVertical position of the label relative to the control
labelAlign"start" | "center" | "end"centerNoHorizontal alignment of the label text
labelOverflow"ellipsis" | "abbreviate" | "auto"autoNoHow to handle label text overflow
labelHeightUnitsnumberNoLabel height in the same units as SVG viewBox height
parameterDiscreteParameterNoAudio Parameter definition (Model). If provided, overrides label/options from ad-hoc props
paramIdstringNoIdentifier for the parameter this control represents
midiResolutionMidiResolution7NoMIDI resolution in bits (ad-hoc mode, ignored if parameter provided)
midiMapping"spread" | "sequential" | "custom"spreadNoMIDI mapping strategy (ad-hoc mode, ignored if parameter provided)
onClickReact.MouseEventHandlerNoClick event handler
onMouseDownReact.MouseEventHandlerNoMouse down event handler
onMouseUpReact.MouseEventHandlerNoMouse up event handler
onMouseEnterReact.MouseEventHandlerNoMouse enter event handler
onMouseLeaveReact.MouseEventHandlerNoMouse leave event handler
classNamestringNoAdditional CSS classes
styleReact.CSSPropertiesNoAdditional inline styles

Understanding Options vs Children

The CycleButton component distinguishes between two concepts:

  • options prop: Defines the parameter model (value, label, midiValue). Used for parameter structure.
  • children (OptionView components): Provides visual content (ReactNodes) for rendering. Used for display.

These serve different purposes and can be used together:

  • Use options when you have data-driven option definitions
  • Use children when you want to provide custom visual content (icons, styled text, etc.)
  • Use both: options for the model, children for visuals (matched by value)

Note:

Basic use: For basic use of CycleButton, and especially when using ad-hoc props (no parameter prop), prefer OptionView children. In that case the option set is inferred from the OptionViews: you declare each option once as <OptionView value="...">...</OptionView>, and the same children are used for display. Use the options prop or a full parameter when you need explicit parameter structure (e.g. data-driven options, MIDI mapping). For a full disambiguation of options vs OptionView, see Options vs OptionView.

Modes of Operation

The CycleButton component supports four modes of operation:

1. Ad-Hoc Mode (Options prop)

Model from options prop, visual from children (if provided) or default rendering:

OptionsPropMode.tsx

2. Ad-Hoc Mode (Children only)

Model inferred from OptionView children, visual from children:

ChildrenOnlyMode.tsx

3. Strict Mode (Parameter only)

Model from parameter prop, visual via renderOption callback. The following example uses children (OptionView); with the full library you would use createDiscreteParameter and the parameter prop:

StrictMode.tsx

4. Hybrid Mode (Parameter + Children)

Model from parameter prop, visual from children (matched by value):

HybridMode.tsx

Using OptionView

The OptionView component is used to provide visual content for each option. It accepts any ReactNode as children:

Text Content

TextOptionView.tsx

Icon Content

IconOptionView.tsx

Custom Components

CustomOptionView.tsx
OptionViewExample.tsx

Theming

Vector components share common theming features; see Theming Features in the Vector introduction for an overview. The CycleButton component supports theming through the color and roundness props:

Color Customization

CycleButtonColor.tsx

Roundness

Control the roundness of the knob ring:

CycleButtonRoundness.tsx

Thickness

Adjust the stroke thickness:

CycleButtonThickness.tsx

Ring Configuration

Openness

Control how much of the ring is visible:

CycleButtonOpenness.tsx

Rotation

Offset the starting angle of the ring:

CycleButtonRotation.tsx

Adaptive Sizing

The CycleButton component supports both fixed sizes and adaptive sizing. By default, the size of the component is driven by the Size System and their size attribute:

CycleButtonSizing.tsx

Adaptive sizing allows the component to adapt to the size of its parent container, adjusting its dimensions intelligently without causing distortion (scaleToFit display mode). The fill display mode makes the component fill the entire container, potentially distorting it.

CycleButtonAdaptiveSize.tsx

Controlled vs Uncontrolled

The CycleButton supports both controlled and uncontrolled modes:

Controlled Mode

ControlledMode.tsx

Uncontrolled Mode

UncontrolledMode.tsx

MIDI Integration

When using the options prop or parameter model, you can specify MIDI values for each option:

MIDIIntegration.tsx

Common Patterns

Waveform Selector

A typical waveform selector for synthesizers:

WaveformSelector.tsx

Filter Type Selector

A filter type selector:

FilterTypeSelector.tsx
CommonPatternExample.tsx

Common Use Cases

The Waveform Selector and Filter Type Selector examples above (in Common Patterns) show typical use cases with live demos.

Next Steps