# Fader API


`Fader` is a linear slider drawn to look like a channel fader on a mixing console: a cap slides along a slot, with a configurable tick scale (e.g. dB marks) alongside the track. It is vertical by default with `max_value` at the top; pass `orientation="horizontal"` for a left-to-right fader.


Ticks are configurable — `ticks=N` for evenly spaced marks, a list of values, or `(value, label)` pairs. Pass `steps` instead for a **stepped fader** that snaps to discrete detents. With `midi=True` the fader shows a "MIDI learn" button: click it, move a control on your hardware, and the next control-change message binds to the fader (Web MIDI, Chromium browsers). The binding is remembered in browser localStorage so it survives a restart.


See also: Knob for the rotary console version, and HoverSlider for a linear slider that also reports the value under the pointer.


 Bases: `AnyWidget`


Mixing-console style fader: a cap that slides along a track.


A linear slider drawn to look like a channel fader, with a configurable tick scale (e.g. dB marks) alongside the track. Vertical by default, with `max_value` at the top; pass `orientation="horizontal"` for a left-to-right fader.



```
from wigglystuff import Fader

import marimo as mo
from wigglystuff import Fader

level = mo.ui.anywidget(
    Fader(min_value=-60, max_value=6, value=0, ticks=[-60, -20, -6, 0, 6],
          label="Level")
)
level
```


Create a Fader.


  Source code in `wigglystuff/fader.py`

```
def __init__(
    self,
    value: Optional[float] = None,
    min_value: float = 0.0,
    max_value: float = 100.0,
    step: float = 1.0,
    ticks: TickSpec = None,
    steps: Optional[Sequence[Any]] = None,
    orientation: str = "vertical",
    length: int = 200,
    label: str = "",
    show_value: bool = True,
    color: str = "",
    midi: bool = False,
    midi_cc: int = -1,
    midi_channel: int = -1,
    midi_key: str = "",
    midi_scope: Optional[str] = None,
    **kwargs: Any,
) -> None:
    """Create a Fader.

    Args:
        value: Initial value; defaults to ``min_value``. Clamped to range.
        min_value: Lower bound of the value range (bottom / left).
        max_value: Upper bound of the value range (top / right).
        step: Snap increment in value units (must be > 0).
        ticks: Tick/scale marks. ``None`` for none, an int ``N`` for ``N``
            evenly spaced ticks, a list of values, or a list of
            ``(value, label)`` pairs.
        steps: Discrete detents to snap to (a stepped fader). Same shape as
            ``ticks`` — numbers or ``(value, label)`` pairs. When given,
            ``min_value``/``max_value`` are derived from the steps, the
            detents double as the ticks, and dragging snaps to the nearest
            one. Mutually exclusive with ``ticks``.
        orientation: ``"vertical"`` (default) or ``"horizontal"``.
        length: Track length in pixels (the long dimension).
        label: Optional text label shown above the fader.
        show_value: Render the current value as text next to the fader.
        color: Optional CSS color for the filled track and cap. Empty
            string uses the theme default.
        midi: Show a "MIDI learn" button. Click it, then move a control on
            your hardware; the next control-change (CC) message binds to
            this fader and drives its value. Uses the Web MIDI API (Chromium
            browsers, secure context). Read the binding back via
            ``midi_cc`` / ``midi_channel`` / ``midi_device``.
        midi_cc: Bind a control-change number (0-127) up front instead of
            learning it. ``-1`` (default) leaves it unbound.
        midi_channel: MIDI channel (0-15) for the binding, or ``-1`` for any.
        midi_key: localStorage key for persisting the learned binding across
            restarts. Defaults to ``label``. Empty (no label either) disables
            persistence.
        midi_scope: Namespace for the persisted binding, so different
            notebooks don't collide. Empty (default) uses the browser's URL
            path automatically; pass an explicit string to pin it (or to
            intentionally share a mapping across notebooks).
        **kwargs: Forwarded to ``anywidget.AnyWidget``.
    """
    if midi_scope is None:
        midi_scope = ""
    if step <= 0:
        raise ValueError("step must be positive.")
    if orientation not in _ORIENTATIONS:
        raise ValueError(
            f"orientation must be one of {_ORIENTATIONS}, got {orientation!r}."
        )

    if steps is not None:
        if ticks is not None:
            raise ValueError("`ticks` is mutually exclusive with `steps`.")
        step_values = normalize_steps(steps)
        min_value, max_value = step_values[0], step_values[-1]
        tick_dicts = normalize_ticks(steps, min_value, max_value)
        if value is None:
            value = step_values[0]
        else:
            value = min(step_values, key=lambda s: abs(s - float(value)))
    else:
        step_values = []
        if min_value >= max_value:
            raise ValueError("min_value must be less than max_value.")
        tick_dicts = normalize_ticks(ticks, min_value, max_value)
        if value is None:
            value = min_value
        value = clamp(float(value), min_value, max_value)

    super().__init__(
        value=float(value),
        min_value=float(min_value),
        max_value=float(max_value),
        step=float(step),
        ticks=tick_dicts,
        steps=step_values,
        orientation=orientation,
        length=length,
        label=label,
        show_value=show_value,
        color=color,
        midi=midi,
        midi_cc=midi_cc,
        midi_channel=midi_channel,
        midi_key=midi_key,
        midi_scope=midi_scope,
        **kwargs,
    )
```


## Synced traitlets


| Traitlet | Type | Notes |
| --- | --- | --- |
| `value` | `float` | Current value, mapped along the track. |
| `min_value` | `float` | Lower bound (bottom / left). |
| `max_value` | `float` | Upper bound (top / right). |
| `step` | `float` | Snap increment in value units (continuous mode). |
| `ticks` | `list[dict]` | Normalized `{"value", "label"}` tick marks. |
| `steps` | `list[float]` | Discrete detents to snap to; empty means continuous. |
| `orientation` | `str` | `"vertical"` (default) or `"horizontal"`. |
| `length` | `int` | Track length in pixels (the long dimension). |
| `label` | `str` | Optional text label shown above the fader. |
| `show_value` | `bool` | Render the current value as text next to the fader. |
| `color` | `str` | CSS color for the filled track and cap. Empty follows the theme. |
| `midi` | `bool` | Show the MIDI-learn button and listen for control-change. |
| `midi_cc` | `int` | Bound control-change number (0-127), or `-1` when unbound. |
| `midi_channel` | `int` | Bound MIDI channel (0-15), or `-1` for any. |
| `midi_device` | `str` | Name of the bound MIDI input device. |
| `midi_supported` | `bool` | Whether the browser exposes Web MIDI (set from JS). |
| `midi_learning` | `bool` | Whether the fader is currently in learn mode. |
| `midi_key` | `str` | localStorage key for the persisted binding (defaults to `label`). |
| `midi_scope` | `str` | Namespace for the binding; empty uses the browser URL path. |
