Demo

section_scrollbar
section_scrollbar is a pure Flutter package for building a section-aware
custom scrollbar that shows a floating badge for the current section while the
user scrolls.
It is not a platform scrollbar skin. The package measures your declared
sections, tracks the active one with a configurable viewport probe, and overlays
its own thumb + current-section chip on top of a normal SingleChildScrollView.
Why this package exists
Many scroll experiences are organized into meaningful sections, but a standard scrollbar only communicates raw position. In practice, users often need both: where they are in the scroll range and which logical part of the content they are currently viewing.
section_scrollbar is a general-purpose primitive for any vertically scrolling
surface with structured sections, including:
- landing pages
- portfolio sites
- documentation pages
- dashboards
- reports
- settings screens
- onboarding flows
- long-form content experiences
It keeps the familiar scrollbar interaction model and adds a lightweight, rounded badge containing:
- the active section label
- the active section icon, if provided
- a stable section-aware controller API you can use for custom UI
Features
- Section definitions with ids, labels, and optional icons
- Explicit section anchors for accurate layout measurement
- Active-section detection with configurable probe strategies
- Right-side custom scrollbar overlay for
SingleChildScrollView - Floating badge that appears while scrolling
scrollTo(id)andrecompute()on aChangeNotifiercontroller- Immutable public state for custom builders and advanced effects
- Pure Flutter implementation for mobile, web, and desktop
Installation
flutter pub add section_scrollbar
Quick Start
import 'package:flutter/material.dart';
import 'package:section_scrollbar/section_scrollbar.dart';
final sectionController = SectionScrollbarController();
final scrollController = ScrollController();
SectionScrollbarLayout(
controller: sectionController,
scrollController: scrollController,
sections: const [
SectionData(
id: 'intro',
label: 'Intro',
icon: Icons.waving_hand_rounded,
),
SectionData(
id: 'work',
label: 'Work',
icon: Icons.work_outline_rounded,
),
SectionData(
id: 'metrics',
label: 'Metrics',
icon: Icons.query_stats_rounded,
),
SectionData(
id: 'contact',
label: 'Contact',
icon: Icons.mail_outline_rounded,
),
],
config: const SectionScrollbarConfig(
activationStrategy: SectionActivationStrategy.quarterViewport,
),
child: SingleChildScrollView(
controller: scrollController,
child: Column(
children: const [
SectionAnchor(id: 'intro', child: IntroSection()),
SectionAnchor(id: 'work', child: WorkSection()),
SectionAnchor(id: 'metrics', child: MetricsSection()),
SectionAnchor(id: 'contact', child: ContactSection()),
],
),
),
);
How it works
- Define your sections with
SectionData. - Wrap each real content section with
SectionAnchor. - Place everything inside
SectionScrollbarLayout. - The controller measures anchors after layout.
- On scroll, the controller resolves the active section and computes:
- page progress
- progress within the active section
- thumb size
- thumb offset
- active badge payload
- The default scrollbar renders a subtle track, a thumb, and a floating badge while scrolling.
Public API
SectionData
Declares a logical section.
Fields:
idlabeliconweight
SectionAnchor
Wraps each measured content section and registers it with the nearest
SectionScrollbarLayout.
SectionScrollbarController
The main ChangeNotifier that owns:
- section registration
- metric recomputation
- active-section detection
scrollTo(id)- immutable
state
SectionScrollbarConfig
Controls behavior and default layout values.
Key fields:
activationStrategyscrollAnimationDurationscrollAnimationCurveoverlayWidthtrackThicknessthumbThicknessminThumbExtentbadgeSpacingvisibilityAnimationDurationalwaysShowScrollbar
SectionScrollbarState
Immutable derived state exposed by the controller.
Key fields:
activeSectionIdactiveSectionLabelactiveSectionIconitemsscrollProgressactiveSectionProgressthumbOffsetFractionthumbExtentFractionhasMetricsisScrollActive
SectionScrollbarVisualItem
Per-section render data for custom overlays and builders.
SectionScrollbarLayout
Wraps your scroll view and places the overlay scrollbar on top of it.
SectionScrollbar
Generic scrollbar shell for custom track/thumb/badge builders.
DefaultSectionScrollbar
Default implementation that renders:
- a subtle vertical track
- a rounded thumb
- a rounded floating badge containing the active section metadata
Customization
You can customize at two levels:
1. Config-only customization
Use SectionScrollbarConfig when you only want to tune sizing, animation, or
visibility behavior.
2. Full overlay customization
Pass scrollbarBuilder to SectionScrollbarLayout and render your own overlay
from the controller state.
The SectionScrollbarState.items list gives you section-level fractions and
progress values so you can build custom markers, painters, or richer badges.
Example
The example app in example/lib/main.dart demonstrates:
- four tracked sections
- the default floating badge behavior
- controller-driven
scrollTo - varying section heights
Limitations in v1
- Vertical scrolling only
- Designed for one main
ScrollController - Supports
SingleChildScrollView, not slivers or nested scroll views - The default scrollbar is passive; thumb dragging is not implemented in v1
- Requires explicit
SectionAnchorwidgets for measured sections
Roadmap
- Interactive thumb dragging
- Sliver support
- Nested scroll coordination
- Horizontal mode
- Accessibility improvements for keyboard and semantics
- More default badge and thumb styles
Libraries
- section_scrollbar
- A section-aware custom scrollbar package for Flutter.