# FloatingPanel API


`FloatingPanel` wraps any marimo content in a `position: fixed` panel that stays in view while the notebook scrolls, is draggable by its header, and minimizes to just that header with the `−` toggle. It is a marimo display helper rather than an `AnyWidget`, and the wrapped content stays live — keep your own reference and read `.value` as usual.


Unlike Pip, which moves a widget into a separate Picture-in-Picture window, the panel is an ordinary element in the page, so it also works inside an iframe such as molab.


See also: Pip for floating a widget in a real OS window, and Hint and WidgetDAG for other marimo-only display helpers.


Pin any marimo content in a draggable panel that floats above the page.


Wraps `child` in a `position: fixed` panel that stays in view while the notebook scrolls, is draggable by its header, and can be minimized. Unlike `Pip` (which opens a separate Picture-in-Picture window), the panel is an ordinary element in the page, so it also works inside an iframe such as molab. This is a marimo-only display helper, not an `AnyWidget`: display it as the last expression of a cell and keep reading `.value` off the widgets you passed in -- they stay fully live.


A `FloatingPanel` renders as ordinary marimo content, so it composes: the `child` can be a single `mo.ui` element, an `mo.vstack`/`mo.hstack` layout, a chart, an image, or a wigglystuff widget.


  Example

```
import marimo as mo
from wigglystuff import FloatingPanel

slider = mo.ui.slider(1, 10, label="N")
FloatingPanel(slider, corner="top-right")
```

  Source code in `wigglystuff/floating_panel.py`

```
def __init__(
    self,
    child: Any,
    *,
    corner: str = "bottom-right",
    width: Optional[int] = None,
    collapsed: bool = False,
) -> None:
    if corner not in CORNERS:
        raise ValueError(f"corner must be one of {CORNERS}, got {corner!r}")
    if width is not None and width <= 0:
        raise ValueError(f"width must be positive, got {width}")
    self.child = child
    self.corner = corner
    self.width = width
    self.collapsed = collapsed
    self._html = None
```


## Parameters


`FloatingPanel` is a display helper, not an `AnyWidget`, so it has no synced traitlets. Everything is set once at construction.


| Parameter | Type | Notes |
| --- | --- | --- |
| `child` | any | The content to float. Anything marimo can render: an `mo.ui` element, an `mo.vstack`/`mo.hstack` layout, a figure, an image, another wigglystuff widget, or plain markdown. |
| `corner` | `str` | Where the panel starts before it is dragged: `"top-left"`, `"top-right"`, `"bottom-left"` or `"bottom-right"`. Anything else raises `ValueError`. |
| `width` | `int` or `None` | Panel width in pixels. Defaults to `None`, which shrink-wraps the panel to its content — the right choice for most content, since marimo widgets keep their own width. Set an integer for a fixed width, e.g. to reflow long text. A non-positive width raises `ValueError`. |
| `collapsed` | `bool` | Start minimized, showing only the draggable header. The header's `−`/`+` toggle collapses and expands it; nothing is ever fully dismissed. |


## Notes


`FloatingPanel` is a marimo-only display helper. A companion overlay reaches into marimo's rendered DOM to build the drag header, pin the panel, and — crucially — portal the panel to `document.body` so its `z-index` wins over every cell (a panel left inside a cell is painted under any cell marimo raises on hover). It is not wired for plain Jupyter and raises a clear `RuntimeError` there. Both `marimo edit` and `marimo run` work; marimo *script* mode (`python demo.py`) does not, because there is no rendered DOM to draw into.


The floated content stays live and reactive. Keep your own reference to it and read `.value` as usual — `FloatingPanel` never sits between you and your data:


```
slider = mo.ui.slider(1, 10, label="N")
FloatingPanel(slider, corner="top-right")   # in one cell
slider.value                                 # still works in another
```


A panel can still be covered by marimo's *own* fixed chrome (the top search bar, the corner action buttons); just drag it to a clear spot.
