Scrollbar
Properties
-
interactive(bool | None) –Whether this scroll bar should be interactive and respond to dragging on the
-
orientation(ScrollbarOrientation | None) –Specifies where the scrollbar should appear relative to the scrollable.
-
radius(Number | None) –Circular radius of the scrollbar thumb's rounded rectangle corners in logical
-
thickness(Number | None) –Controls the cross-axis size of the scrollbar in logical pixels.
-
thumb_visibility(bool | None) –Whether this scrollbar's thumb should be always be visible, even when not being
-
track_visibility(bool | None) –Indicates whether the scrollbar track should be visible,
Examples#
Showcase#
from typing import Optional
import flet as ft
def parse_optional_bool(value: Optional[str]):
if value == "true":
return True
if value == "false":
return False
return None
def main(page: ft.Page):
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.appbar = ft.AppBar(title="Scrollbar Dataclass Showcase")
thumb_visibility = ft.Dropdown(
label="thumb_visibility",
value="none",
options=[
ft.dropdown.Option("none", "None (theme/default)"),
ft.dropdown.Option("true", "True"),
ft.dropdown.Option("false", "False"),
],
)
track_visibility = ft.Dropdown(
label="track_visibility",
value="none",
options=[
ft.dropdown.Option("none", "None (theme/default)"),
ft.dropdown.Option("true", "True"),
ft.dropdown.Option("false", "False"),
],
)
interactive = ft.Dropdown(
label="interactive",
value="none",
options=[
ft.dropdown.Option("none", "None (platform default)"),
ft.dropdown.Option("true", "True"),
ft.dropdown.Option("false", "False"),
],
)
orientation = ft.Dropdown(
label="orientation",
value="none",
options=[ft.dropdown.Option("none", "None (auto side)")]
+ [ft.dropdown.Option(o.value, o.name) for o in ft.ScrollbarOrientation],
)
use_thickness = ft.Checkbox(label="Set thickness", value=False)
thickness_value = ft.Slider(min=0, max=20, divisions=20, value=8, label="{value}")
use_radius = ft.Checkbox(label="Set radius", value=False)
radius_value = ft.Slider(min=0, max=20, divisions=20, value=8, label="{value}")
code_preview = ft.TextField(
label="Generated Scrollbar()",
read_only=True,
multiline=True,
min_lines=4,
max_lines=8,
)
current_mode_hint = ft.Text(size=12, color=ft.Colors.ON_SURFACE_VARIANT)
preview_title = ft.Text(weight=ft.FontWeight.BOLD)
preview_viewport = ft.Container(
height=260,
border=ft.Border.all(1, ft.Colors.OUTLINE),
border_radius=8,
padding=8,
)
def parse_orientation():
if orientation.value == "none":
return None
return ft.ScrollbarOrientation(orientation.value)
def build_scrollbar() -> ft.Scrollbar:
thickness = float(thickness_value.value) if use_thickness.value else None
radius = float(radius_value.value) if use_radius.value else None
return ft.Scrollbar(
thumb_visibility=parse_optional_bool(thumb_visibility.value),
track_visibility=parse_optional_bool(track_visibility.value),
interactive=parse_optional_bool(interactive.value),
thickness=thickness,
radius=radius,
orientation=parse_orientation(),
)
def build_scrollbar_code(scrollbar: ft.Scrollbar) -> str:
args: list[str] = []
if scrollbar.thumb_visibility is not None:
args.append(f"thumb_visibility={scrollbar.thumb_visibility}")
if scrollbar.track_visibility is not None:
args.append(f"track_visibility={scrollbar.track_visibility}")
if scrollbar.interactive is not None:
args.append(f"interactive={scrollbar.interactive}")
if scrollbar.thickness is not None:
thickness = (
int(scrollbar.thickness)
if float(scrollbar.thickness).is_integer()
else scrollbar.thickness
)
args.append(f"thickness={thickness}")
if scrollbar.radius is not None:
radius = (
int(scrollbar.radius)
if float(scrollbar.radius).is_integer()
else scrollbar.radius
)
args.append(f"radius={radius}")
if scrollbar.orientation is not None:
args.append(
f"orientation=ft.ScrollbarOrientation.{scrollbar.orientation.name}"
)
if not args:
return "ft.Scrollbar()"
return "ft.Scrollbar(\n" + "".join([f" {arg},\n" for arg in args]) + ")"
def build_preview_content(scrollbar: ft.Scrollbar) -> tuple[str, ft.Control]:
selected_orientation = scrollbar.orientation
is_horizontal = selected_orientation in (
ft.ScrollbarOrientation.TOP,
ft.ScrollbarOrientation.BOTTOM,
)
if is_horizontal:
return (
"Horizontal preview (TOP/BOTTOM orientation)",
ft.Row(
spacing=8,
scroll=scrollbar,
controls=[
ft.Container(
width=110,
height=80,
border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT),
border_radius=8,
bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST,
alignment=ft.Alignment.CENTER,
content=ft.Text(f"Tile {i + 1}"),
)
for i in range(18)
],
),
)
return (
"Vertical preview (None/LEFT/RIGHT orientation)",
ft.Column(
spacing=4,
scroll=scrollbar,
controls=[ft.Text(f"Item {i + 1}") for i in range(40)],
),
)
def mode_hint(scrollbar: ft.Scrollbar) -> str:
if scrollbar.thickness == 0:
return "Equivalent legacy mode: ScrollMode.HIDDEN"
thumb = scrollbar.thumb_visibility
thickness = scrollbar.thickness
mobile_default_thickness = (
4.0 if page.platform.is_mobile() and not page.web else None
)
if thumb is True and thickness == mobile_default_thickness:
return "Equivalent legacy mode: ScrollMode.ALWAYS"
if (
thumb == (not (page.platform.is_mobile() and not page.web))
and thickness == mobile_default_thickness
):
return "Equivalent legacy mode: ScrollMode.ADAPTIVE"
if thumb is None and thickness == mobile_default_thickness:
return "Equivalent legacy mode: ScrollMode.AUTO"
return "Custom configuration (no exact ScrollMode equivalent)"
def update_preview(_=None):
thickness_value.disabled = not use_thickness.value
radius_value.disabled = not use_radius.value
scrollbar = build_scrollbar()
title, content = build_preview_content(scrollbar)
preview_title.value = title
preview_viewport.content = content
code_preview.value = build_scrollbar_code(scrollbar)
current_mode_hint.value = mode_hint(scrollbar)
page.update()
dropdowns = [thumb_visibility, track_visibility, interactive, orientation]
for c in dropdowns:
c.on_select = update_preview
controls_with_on_change = [use_thickness, thickness_value, use_radius, radius_value]
for c in controls_with_on_change:
c.on_change = update_preview
page.add(
ft.Text(
"Interactive playground for the Scrollbar dataclass. Change each property "
"and inspect the live result."
),
ft.Row(
wrap=True,
spacing=12,
run_spacing=12,
alignment=ft.MainAxisAlignment.CENTER,
controls=[
ft.Container(
width=360,
padding=12,
border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT),
border_radius=10,
bgcolor=ft.Colors.SURFACE_CONTAINER_LOW,
content=ft.Column(
spacing=10,
controls=[
ft.Text("Configuration", weight=ft.FontWeight.BOLD),
thumb_visibility,
track_visibility,
interactive,
orientation,
use_thickness,
thickness_value,
use_radius,
radius_value,
],
),
),
ft.Container(
width=420,
padding=12,
border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT),
border_radius=10,
bgcolor=ft.Colors.SURFACE_CONTAINER_LOW,
content=ft.Column(
spacing=10,
controls=[
ft.Text("Live preview", weight=ft.FontWeight.BOLD),
preview_title,
preview_viewport,
current_mode_hint,
code_preview,
],
),
),
],
),
)
update_preview()
ft.run(main)
Properties#
interactive
class-attribute
instance-attribute
#
interactive: bool | None = None
Whether this scroll bar should be interactive and respond to dragging on the thumb, or tapping in the track area.
When False, the scrollbar will not respond to gesture or hover events, and will
allow to click through it.
If None, defaults to True, unless on Android, where it defaults to False.
orientation
class-attribute
instance-attribute
#
orientation: ScrollbarOrientation | None = None
Specifies where the scrollbar should appear relative to the scrollable.
If None, for a vertical scroll, defaults to ScrollbarOrientation.RIGHT
for left-to-right text direction and ScrollbarOrientation.LEFT
for right-to-left text direction, while for a horizontal scroll, it defaults to
ScrollbarOrientation.BOTTOM.
Note
ScrollbarOrientation.TOP and ScrollbarOrientation.BOTTOM
can only be used with a vertical scroll; ScrollbarOrientation.LEFT
and ScrollbarOrientation.RIGHT can only be used with a horizontal
scroll.
radius
class-attribute
instance-attribute
#
radius: Number | None = None
Circular radius of the scrollbar thumb's rounded rectangle corners in logical
pixels. If None, platform defaults are used.
The radius of the scrollbar thumb's rounded rectangle corners.
If None, the default value is platform dependent:
no radius is applied on Android
(Page.platform == PagePlatform.ANDROID);
1.5 pixels on iOS (Page.platform == PagePlatform.IOS);
8.0 pixels on the remaining platforms.
thickness
class-attribute
instance-attribute
#
thickness: Number | None = None
Controls the cross-axis size of the scrollbar in logical pixels. The thickness of the scrollbar in the cross axis of the scrollable.
If None, the default value is platform dependent:
4.0 pixels on Android
(Page.platform == PagePlatform.ANDROID);
3.0 pixels on iOS (Page.platform == PagePlatform.IOS);
8.0 pixels on the remaining platforms.
thumb_visibility
class-attribute
instance-attribute
#
thumb_visibility: bool | None = None
Whether this scrollbar's thumb should be always be visible, even when not being
scrolled. When False, the scrollbar will be shown during scrolling and
will fade out otherwise.
If None, then ScrollbarTheme.thumb_visibility is used.
If that is also None, defaults to False.
track_visibility
class-attribute
instance-attribute
#
track_visibility: bool | None = None
Indicates whether the scrollbar track should be visible, so long as the thumb is visible.
If None, then ScrollbarTheme.track_visibility is used.
If that is also None, defaults to False.