# HoverSlider API


`HoverSlider` treats hovering as an input channel of its own: `hover_value` follows the pointer while `value` stays parked where you last clicked, so a cell can show you what a setting would do before you commit to it. Pass `start`/`stop`/`step` for a linear range or `steps` for a list of discrete values, and use `sync_throttle_ms` to cap how often the hover stream reruns downstream cells.


See also: PlaySlider for stepping through a range on a timer, CircularSlider for the same range laid out on a dial, and TangleSlider for a draggable number that lives inside a sentence.


 Bases: `AnyWidget`


Horizontal slider that reports both a committed value and a live hover value.


Hovering the track is an input channel of its own: `hover_value` follows the pointer while `value` stays parked where you last clicked. That lets a notebook preview a result before you commit to it. Click (or drag the puck) to move `value`; when the pointer leaves the track `hover_value` falls back to `value`, so it is never `None`.


Mirrors `mo.ui.slider` semantics: pass `start`/`stop`/`step` for a linear range, or `steps` for a list of discrete values (the two are mutually exclusive). Numeric types are preserved -- `steps=[1, 2, 3]` hands back an `int`, `steps=[1, 2.5, 4]` hands back floats.

 Note

Hover fires a *lot*. Because `mo.ui.anywidget` reruns dependent cells on every synced trait change, `sync_throttle_ms` is the knob that decides how hard this widget hits your notebook: the default of 100ms caps it at roughly 10 reruns per second while the pointer sweeps. Raise it if downstream cells are expensive; set it to `0` to sync every single pointer move.



```
from wigglystuff import HoverSlider

import marimo as mo
from wigglystuff import HoverSlider

slider = mo.ui.anywidget(HoverSlider(start=0, stop=100, step=1, value=42))
slider
```


```
# `hover_value` previews, `value` is what the user actually committed.
mo.md(f"previewing {slider.value['hover_value']}, committed {slider.value['value']}")
```


Create a HoverSlider.


  Source code in `wigglystuff/hover_slider.py`

```
def __init__(
    self,
    start: Optional[float] = None,
    stop: Optional[float] = None,
    step: Optional[float] = None,
    steps: Optional[Sequence[float]] = None,
    value: Optional[float] = None,
    sync_throttle_ms: int = 100,
    show_value: bool = True,
    label: str = "",
    color: str = "",
    width: int = 400,
    **kwargs: Any,
) -> None:
    """Create a HoverSlider.

    Args:
        start: Lower bound of the range. Defaults to ``0``.
        stop: Upper bound of the range. Defaults to ``100``.
        step: Snap increment (must be > 0). Defaults to ``1``.
        steps: List of discrete values to snap to, laid out evenly across the
            track regardless of spacing. Mutually exclusive with
            ``start``/``stop``/``step``. Needs at least two entries.
        value: Initial committed value; defaults to ``start`` (or ``steps[0]``).
            Snapped into range.
        sync_throttle_ms: Cap on how often hover/drag updates reach Python, in
            milliseconds. ``0`` syncs on every pointer move.
        show_value: Render the committed and hovered values as text below the track.
        label: Optional text label shown above the track. Empty string hides it.
        color: Optional CSS color (e.g. ``"#ef4444"``, ``"tomato"``) for the fill,
            puck border, and hover marker. Empty string uses the theme default.
        width: Widget width in pixels.
        **kwargs: Forwarded to ``anywidget.AnyWidget``.
    """
    if steps is not None and (
        start is not None or stop is not None or step is not None
    ):
        raise ValueError(
            "Invalid arguments: `steps` is mutually exclusive with "
            "`start`, `stop`, and `step`."
        )

    if steps is not None:
        steps = _as_list(steps)
        if not all(_is_number(s) for s in steps):
            raise TypeError("Invalid steps: steps must be a sequence of numbers.")
        if len(steps) < 2:
            raise ValueError("Must pass at least two steps.")
        dtype = _infer_dtype(list(steps) + [value])
        steps = [_cast(s, dtype) for s in steps]
        value = steps[0] if value is None else _nearest(steps, value)
        start, stop, step = steps[0], steps[-1], None
    else:
        start = 0 if start is None else start
        stop = 100 if stop is None else stop
        step = 1 if step is None else step
        if not all(_is_number(x) for x in (start, stop, step)):
            raise TypeError("start, stop and step must be numbers.")
        if value is not None and not _is_number(value):
            raise TypeError("value must be a number.")
        if start >= stop:
            raise ValueError("start must be less than stop.")
        if step <= 0:
            raise ValueError("step must be positive.")
        dtype = _infer_dtype([start, stop, step, value])
        start, stop, step = (
            _cast(start, dtype),
            _cast(stop, dtype),
            _cast(step, dtype),
        )
        value = _snap_linear(
            start if value is None else value, start, stop, step, dtype
        )
        steps = []

    # Pass value *and* hover_value explicitly: traitlets skips cross-validation
    # for traits you leave at their class default.
    super().__init__(
        start=start,
        stop=stop,
        step=step,
        steps=steps,
        value=value,
        hover_value=value,
        hovering=False,
        sync_throttle_ms=sync_throttle_ms,
        show_value=show_value,
        label=label,
        color=color,
        width=width,
        **kwargs,
    )
    self.observe(self._mirror_hover_value, names="value")
```


## Synced traitlets


| Traitlet | Type | Notes |
| --- | --- | --- |
| `value` | `int \\| float` | Committed value. Moves on click, drag, and arrow keys — never on plain hover. |
| `hover_value` | `int \\| float` | Value under the pointer. Falls back to `value` when the pointer leaves, so it is never `None`. |
| `hovering` | `bool` | Whether the pointer is on the track, i.e. whether `hover_value` is live. |
| `start` | `int \\| float` | Lower bound. In `steps` mode this is `steps[0]`. |
| `stop` | `int \\| float` | Upper bound. In `steps` mode this is `steps[-1]`. |
| `step` | `int \\| float \\| None` | Snap increment. `None` in `steps` mode. |
| `steps` | `list[int \\| float]` | Discrete values, laid out evenly across the track. Empty means linear mode. |
| `sync_throttle_ms` | `int` | Cap on how often hover updates reach Python. `0` syncs every pointer move. |
| `show_value` | `bool` | Render the committed and hovered values below the track. |
| `label` | `str` | Text above the track. Empty string hides it. |
| `color` | `str` | CSS color for the fill, puck border, and hover marker. Empty uses the theme default. |
| `width` | `int` | Widget width in pixels. |
