# Scrolling (/examples/scroll)



Any `lv_obj_t` whose content exceeds its bounds can scroll, with per-axis control and optional snap points that lock motion to child boundaries. Scrollbars are themeable through the `LV_PART_SCROLLBAR` style part, and event callbacks let you translate, fade, or scale children as they move through the viewport. The examples cover scrollbar mode and styling, RTL placement, the scrollable/chain/snap/scroll-one/floating behaviors, scroll events, programmatic scrolling, and the infinite and circular scroll patterns.

Scroll chaining [#scroll-chaining]

<LvglExampleBrief>
  A nested scrollable can stop scrolling from propagating to its parent.
</LvglExampleBrief>

The outer panel scrolls, and it contains an inner scrollable box that
also overflows. By default, reaching the inner box's edge would "chain"
the remaining scroll to the outer panel. Setting `scroll_chain="false"`
on the inner box breaks that link, so scrolling stops at the box and
the outer panel does not move.

<LvglExample name="lv_example_scroll_chain" path="scroll/lv_example_scroll_chain" />

Endless circular scrolling [#endless-circular-scrolling]

<LvglExampleBrief>
  Wrap items from one edge to the other so a strip scrolls without limits.
</LvglExampleBrief>

A row strip and a column strip each hold ten buttons. Their
`LV_EVENT_SCROLL` callback detects when either edge is reached and uses
`lv_obj_move_to_index` to move the boundary child across, then
compensates with `lv_obj_scroll_to_x/y` so the visible content does not
jump — making the finite list feel infinite in both directions.

<LvglExample name="lv_example_scroll_circular" path="scroll/lv_example_scroll_circular" />

Reacting to scroll events [#reacting-to-scroll-events]

<LvglExampleBrief>
  Read the live scroll position from an LV_EVENT_SCROLL callback.
</LvglExampleBrief>

A panel overflows with buttons so it can be scrolled. On every
`LV_EVENT_SCROLL` the handler reads `lv_obj_get_scroll_y`,
`lv_obj_get_scroll_top` and `lv_obj_get_scroll_bottom` and writes them
into a label, so the numbers update continuously as the panel is
dragged — the typical way to drive UI from the scroll position.

<LvglExample name="lv_example_scroll_events" path="scroll/lv_example_scroll_events" />

Floating button over a list [#floating-button-over-a-list]

<LvglExampleBrief>
  A floating child stays pinned while the list behind it scrolls.
</LvglExampleBrief>

The panel is a scrollable list of buttons. The round "+" button sets
`floating="true"`: a floating child is ignored by the layout and is not
moved when its parent scrolls, so it stays anchored to the bottom-right
corner while the list slides underneath it.

<LvglExample name="lv_example_scroll_floating" path="scroll/lv_example_scroll_floating" />

Infinite (virtualized) scrolling [#infinite-virtualized-scrolling]

<LvglExampleBrief>
  Create rows on demand and delete far-off ones while a column scrolls.
</LvglExampleBrief>

A column tracks the highest and lowest loaded numbers. The
`LV_EVENT_SCROLL` callback appends or prepends rows while either edge
is within 200 px of content end, and deletes rows once they are more
than 600 px away, compensating each change with `lv_obj_scroll_by` so
the view stays steady. This keeps the element count bounded no matter
how far the user scrolls.

<LvglExample name="lv_example_scroll_infinite" path="scroll/lv_example_scroll_infinite" />

Scroll one at a time [#scroll-one-at-a-time]

<LvglExampleBrief>
  Restrict each scroll gesture to a single snappable child.
</LvglExampleBrief>

The panel combines centre snapping with `scroll_one="true"`. Snapping
alone lets a fast fling cross several panels before settling; with
"scroll one" enabled every gesture advances by exactly one panel, no
matter how hard it is thrown. It requires snappable children and a
snap mode other than `none`.

<LvglExample name="lv_example_scroll_one" path="scroll/lv_example_scroll_one" />

Scroll basics [#scroll-basics]

<LvglExampleBrief>
  A panel becomes scrollable on its own when its children overflow it.
</LvglExampleBrief>

The panel is only 140 px tall but stacks six full-width buttons, so the
content is taller than the panel. LVGL makes the panel scrollable and
shows a vertical scrollbar automatically — no scroll-specific API is
used here, only content that exceeds the bounds.

<LvglExample name="lv_example_scroll_overview" path="scroll/lv_example_scroll_overview" />

Toggling scroll behaviour flags [#toggling-scroll-behaviour-flags]

<LvglExampleBrief>
  Switch SCROLLABLE, SCROLL_CHAIN, SCROLL_ELASTIC and SCROLL_MOMENTUM on live.
</LvglExampleBrief>

These four flags change how a Widget reacts to scrolling but only show
their effect through interaction, so one example covers them together.
A scrollable list sits above four switches; each switch toggles the
corresponding behaviour on the list with its dedicated setter (e.g.
`lv_obj_set_scrollable`), so the change can be felt immediately by dragging
the list.

<LvglExample name="lv_example_scroll_properties" path="scroll/lv_example_scroll_properties" />

Right-to-left scrolling [#right-to-left-scrolling]

<LvglExampleBrief>
  An RTL base direction moves the vertical scrollbar to the left side.
</LvglExampleBrief>

`style_base_dir="rtl"` flips the panel's base direction. The vertical
scrollbar is then drawn on the left edge instead of the right, and the
property is inherited, so setting it once on the panel is enough. The
content itself is ordinary so the placement change is the only visible
difference.

<LvglExample name="lv_example_scroll_rtl" path="scroll/lv_example_scroll_rtl" />

Disabling scrolling [#disabling-scrolling]

<LvglExampleBrief>
  Clearing the SCROLLABLE flag clips overflowing content instead of scrolling it.
</LvglExampleBrief>

Both panels hold the same overflowing column of buttons. The left one
keeps the default behaviour and scrolls. The right one sets
`scrollable="false"`, so the flag is cleared: the extra content is
simply clipped and the panel cannot be scrolled at all.

<LvglExample name="lv_example_scroll_scrollable" path="scroll/lv_example_scroll_scrollable" />

Scrollbar mode [#scrollbar-mode]

<LvglExampleBrief>
  Compare an always-hidden scrollbar with an always-visible one.
</LvglExampleBrief>

Two identical overflowing panels differ only in `scrollbar_mode`: the
left one is `off` (scrollable, but the bar is never drawn), the right
one is `on` (the bar is always drawn even when idle). The other modes
are `auto` (bar only while scrollable) and `active` (bar only while
actively scrolling).

<LvglExample name="lv_example_scroll_scrollbar_mode" path="scroll/lv_example_scroll_scrollbar_mode" />

Styling the scrollbar [#styling-the-scrollbar]

<LvglExampleBrief>
  Restyle the SCROLLBAR part into a thick, rounded, coloured bar.
</LvglExampleBrief>

The scrollbar is the `scrollbar` part of any scrollable Widget. A named
style attached with `selector="scrollbar"` overrides its `width`
(thickness), `radius`, fill colour/opacity and `pad_right` (gap from
the edge). `scrollbar_mode="on"` keeps it visible so the styling is
always seen.

<LvglExample name="lv_example_scroll_scrollbar_style" path="scroll/lv_example_scroll_scrollbar_style" />

Scroll snapping [#scroll-snapping]

<LvglExampleBrief>
  Snap children to the centre, and opt one child out of snapping.
</LvglExampleBrief>

The row panel sets `scroll_snap_x="center"`, so when a drag is released
the nearest panel animates to the centre. The third button sets
`snappable="false"`, removing it from the snap candidates: scrolling
glides over it and lands on a neighbouring, snappable panel instead.

<LvglExample name="lv_example_scroll_snap" path="scroll/lv_example_scroll_snap" />

Scrolling programmatically [#scrolling-programmatically]

<LvglExampleBrief>
  Jump, save and restore the scroll position from code with animation.
</LvglExampleBrief>

The panel scrolls because its content overflows. Four buttons drive it
without any user gesture: "Top" and "Bottom" animate to the extremes
via `lv_obj_scroll_to_y` with `LV_ANIM_ON`; "Save" records the current
`lv_obj_get_scroll_y`; "Restore" animates back to the saved offset.

<LvglExample name="lv_example_scroll_to" path="scroll/lv_example_scroll_to" />

Translate children while scrolling [#translate-children-while-scrolling]

<LvglExampleBrief>
  Bow a column of buttons along a circle as they scroll past the centre.
</LvglExampleBrief>

A circular, corner-clipped container snaps its children vertically. An
`LV_EVENT_SCROLL` callback measures each child's offset from the
container centre, projects it onto a circle with `lv_sqrt`, writes the
result to `translate_x`, and fades distant items toward
`LV_OPA_TRANSP` — a parallax effect XML styling cannot express.

<LvglExample name="lv_example_scroll_translate" path="scroll/lv_example_scroll_translate" />
