Scroll Progress
Overview
The scroll progress component displays a visual progress bar that tracks scroll position, providing users with feedback about their reading or navigation progress. It supports both page-level (global) and container-level scroll tracking, making it versatile for various use cases from article reading progress to long-form content navigation.
When to Use
✅ Use scroll progress when:
- Displaying reading progress through long articles or blog posts
- Tracking navigation through lengthy documentation pages
- Providing visual feedback in scrollable containers (modals, sidebars, content areas)
- Enhancing user experience in single-page applications with long content
- Creating a sense of progress in onboarding flows or tutorials
❌ Don't use scroll progress for:
- Short content that doesn't require scrolling
- Replacing proper navigation or table of contents
- Critical information that must be visible without scrolling
- Mobile-first experiences where space is extremely limited
Examples
Default (Global Scroll)
The default scroll progress bar tracks the entire page scroll and is fixed at the top of the viewport:
<div>
<dap-ds-scroll-progress></dap-ds-scroll-progress>
<h1>Scroll Down to See Progress on the top of this page</h1>
</div>
Container Scroll
When a target attribute is provided, the progress bar tracks scroll within a specific container instead of the entire page:
<div style={{ padding: '20px' }}>
<h2>Container Scroll Progress</h2>
<p>The progress bar below tracks scroll within the container.</p>
<div
id="scroll-container"
style={{
height: '300px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)',
marginTop: '20px'
}}>
<dap-ds-scroll-progress target="#scroll-container"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll within this container to see the progress bar update.</p>
{Array(15).fill(0).map((_, i) => (
<p key={i} style={{ margin: '20px 0' }}>
Paragraph {i + 1} - Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
))}
</div>
</div>
</div>
Variant Options
The scroll progress component supports five color variants to match different contexts and themes:
<>
<dap-ds-stack direction="column" style={{ gap: '20px' }}>
<div>
<dap-ds-typography variant="h4">Neutral Variant</dap-ds-typography>
<div
id="variant-neutral"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#variant-neutral" variant="neutral"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
<div>
<dap-ds-typography variant="h4">Brand Variant (Default)</dap-ds-typography>
<div
id="variant-brand"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#variant-brand" variant="brand"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
<div>
<dap-ds-typography variant="h4">Positive Variant</dap-ds-typography>
<div
id="variant-positive"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#variant-positive" variant="positive"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
<div>
<dap-ds-typography variant="h4">Negative Variant</dap-ds-typography>
<div
id="variant-negative"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#variant-negative" variant="negative"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
</dap-ds-stack>
</>
Inverted Variant
The inverted variant is designed for use on dark backgrounds:
<div
style={{
backgroundColor: 'var(--dds-indigo-1000)',
color: 'white',
padding: '20px',
borderRadius: 'var(--dds-radius-md)'
}}>
<h2 style={{ color: 'white' }}>Scroll Progress - Inverted Variant</h2>
<p style={{ color: 'white' }}>For use on dark backgrounds.</p>
<div
id="variant-inverted"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-indigo-700)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-indigo-900)',
marginTop: '20px'
}}>
<dap-ds-scroll-progress target="#variant-inverted" variant="inverted"></dap-ds-scroll-progress>
<div style={{ padding: '20px', color: 'white' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
Size Variants
The scroll progress component comes in three sizes: extra small (2px), small (4px - default), and medium (6px):
<>
<dap-ds-stack direction="column" style={{ gap: '20px' }}>
<div>
<dap-ds-typography variant="h4">Extra Small (2px)</dap-ds-typography>
<div
id="size-xs"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#size-xs" size="xs"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
<div>
<dap-ds-typography variant="h4">Small (4px - Default)</dap-ds-typography>
<div
id="size-sm"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#size-sm" size="sm"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
<div>
<dap-ds-typography variant="h4">Medium (6px)</dap-ds-typography>
<div
id="size-md"
style={{
height: '150px',
overflowY: 'auto',
border: '1px solid var(--dds-neutral-300)',
borderRadius: 'var(--dds-radius-md)',
position: 'relative',
background: 'var(--dds-neutral-50)'
}}>
<dap-ds-scroll-progress target="#size-md" size="md"></dap-ds-scroll-progress>
<div style={{ padding: '20px' }}>
<p>Scroll content 1</p>
<p>Scroll content 2</p>
<p>Scroll content 3</p>
<p>Scroll content 4</p>
<p>Scroll content 5</p>
</div>
</div>
</div>
</dap-ds-stack>
</>
Custom Styling
The scroll progress component supports customization through CSS custom properties and parts.
Quick Customization with CSS Custom Properties
<div>
<dap-ds-scroll-progress
style={{
'--dds-scroll-progress-fill-color-brand': 'var(--dds-violet-600)',
'--dds-scroll-progress-track-color': 'var(--dds-neutral-100)',
'--dds-scroll-progress-transition': 'width 0.2s ease-out'
}}></dap-ds-scroll-progress>
<h1>Custom Styled Progress</h1>
<p>Scroll to see the custom-colored progress bar.</p>
</div>
Importing
Importing React
Tree-Shakeable Imports
For optimal bundle sizes, use the tree-shakeable import syntax:
Attributes
| Property | Type | Default | Description |
|---|
target | string, undefined | | CSS selector for scroll container. If not set, tracks global page scroll. |
| When set, the component uses sticky positioning within the container. | | | |
variant | "neutral", "brand" , "negative" , "positive" , "inverted" | 'brand' | The color variant of the progress indicator. |
size | "xs", "sm" , "md" | 'sm' | The size of the progress bar. |
Slots
No slots available.
Events
No custom events available.
CSS Parts
| Part Name | Description |
|---|
base | The main scroll progress container. |
track | The progress track (background). |
fill | The progress fill bar. |
How to Use CSS Parts
You can style CSS parts using the ::part() pseudo-element selector:
Example usage:
CSS parts allow you to style internal elements of the component while maintaining encapsulation. Learn more in our styling guide.
CSS Custom Properties
| Property Name | Description |
|---|
--dds-scroll-progress-z-index | Z-index for fixed positioning (default: 1000) |
--dds-scroll-progress-transition | Transition for progress updates (default: width 0.1s ease-out) |
--dds-scroll-progress-track-color | Background color of the progress track (default: var(--dds-neutral-200)) |
--dds-scroll-progress-fill-color-neutral | Fill color for neutral variant |
--dds-scroll-progress-fill-color-brand | Fill color for brand variant |
--dds-scroll-progress-fill-color-negative | Fill color for negative variant |
--dds-scroll-progress-fill-color-positive | Fill color for positive variant |
--dds-scroll-progress-fill-color-inverted | Fill color for inverted variant |
How to Use CSS Custom Properties
CSS custom properties (CSS variables) can be set directly on the component or in your stylesheet:
Method 1: Inline styles (Quick customization)
Method 2: CSS classes (Reusable styles)
Method 3: Global theme customization
CSS custom properties inherit through the Shadow DOM, making them perfect for theming. Changes apply immediately without rebuilding.