scroll-to-future 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,970 @@
1
+ # Scroll To Future
2
+
3
+ A customizable React scrollbar component with vertical and horizontal scrolling, draggable thumbs, automatic size calculation, mobile fallback, native scrollbar hiding, and built-in themes.
4
+
5
+ ## Features
6
+
7
+ * Vertical and horizontal scrollbars
8
+ * Automatic thumb sizing
9
+ * Drag-to-scroll support
10
+ * Clickable scrollbar track
11
+ * Support for regular elements and page scrolling
12
+ * Automatic target detection
13
+ * Automatic content and container observation
14
+ * Native scrollbar hiding
15
+ * Native scrolling fallback on mobile devices
16
+ * Overlay and reserved-space positioning
17
+ * Built-in theme presets
18
+ * Fully customizable scrollbar and thumb styles
19
+ * TypeScript support
20
+ * React and Next.js compatible
21
+
22
+ # 20+ Themes in box
23
+ * "primary"
24
+ * "midnight"
25
+ * "neonCyan"
26
+ * "ocean"
27
+ * "deepSea"
28
+ * "forest"
29
+ * "moss"
30
+ * "lava"
31
+ * "ember"
32
+ * "gold"
33
+ * "roseQuartz"
34
+ * "violet"
35
+ * "royal"
36
+ * "arctic"
37
+ * "glass"
38
+ * "graphite"
39
+ * "terminal"
40
+ * "toxic"
41
+ * "candy"
42
+ * "sand"
43
+ * "monoLight"
44
+ * "monoDark";
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install scroll-to-future
50
+ ```
51
+
52
+ ```bash
53
+ yarn add scroll-to-future
54
+ ```
55
+
56
+ ```bash
57
+ pnpm add scroll-to-future
58
+ ```
59
+
60
+
61
+ ## Basic usage
62
+
63
+ ### Improt styles
64
+ ```bash
65
+ import 'scroll-to-future/style.css';
66
+
67
+ The scroll container must have a constrained size and an `overflow` value such as `auto` or `scroll`.
68
+
69
+ ```tsx
70
+ import { ScrollToFuture } from "scroll-to-future";
71
+
72
+ export const Example = () => {
73
+ return (
74
+ <div
75
+ style={{
76
+ position: "relative",
77
+ width: "400px",
78
+ height: "300px",
79
+ overflow: "auto",
80
+ }}
81
+ >
82
+ <ScrollToFuture />
83
+
84
+ <div style={{ minHeight: "1000px" }}>
85
+ Scrollable content
86
+ </div>
87
+ </div>
88
+ );
89
+ };
90
+ ```
91
+
92
+ When `target` is not provided, `ScrollToFuture` automatically uses its parent element as the scroll target.
93
+
94
+ For automatic target detection, place the component directly inside the scrollable container.
95
+
96
+ ## Usage with a target ref
97
+
98
+ Use the `target` property when the scrollbar is rendered outside the scrollable element or when explicit target control is required.
99
+
100
+ ```tsx
101
+ import { useRef } from "react";
102
+ import { ScrollToFuture } from "scroll-to-future";
103
+
104
+ export const Example = () => {
105
+ const scrollRef = useRef<HTMLDivElement>(null);
106
+
107
+ return (
108
+ <div style={{ position: "relative" }}>
109
+ <div
110
+ ref={scrollRef}
111
+ style={{
112
+ width: "400px",
113
+ height: "300px",
114
+ overflow: "auto",
115
+ }}
116
+ >
117
+ <div style={{ minHeight: "1000px" }}>
118
+ Scrollable content
119
+ </div>
120
+ </div>
121
+
122
+ <ScrollToFuture target={scrollRef} />
123
+ </div>
124
+ );
125
+ };
126
+ ```
127
+
128
+ ## Vertical scrollbar
129
+
130
+ ```tsx
131
+ <ScrollToFuture
132
+ scrollBar={{
133
+ mode: "vertical",
134
+ }}
135
+ />
136
+ ```
137
+
138
+ ## Horizontal scrollbar
139
+
140
+ ```tsx
141
+ <div
142
+ style={{
143
+ position: "relative",
144
+ width: "600px",
145
+ overflowX: "auto",
146
+ overflowY: "hidden",
147
+ }}
148
+ >
149
+ <ScrollToFuture
150
+ scrollBar={{
151
+ mode: "horizontal",
152
+ }}
153
+ />
154
+
155
+ <div style={{ width: "1600px", whiteSpace: "nowrap" }}>
156
+ Horizontally scrollable content
157
+ </div>
158
+ </div>
159
+ ```
160
+
161
+ ## Vertical and horizontal scrollbars
162
+
163
+ ```tsx
164
+ <ScrollToFuture
165
+ scrollBar={{
166
+ mode: "both",
167
+ }}
168
+ />
169
+ ```
170
+
171
+ ## Configuration
172
+
173
+ ```tsx
174
+ import type { ScrollToFutureConfig } from "scroll-to-future";
175
+ import "scroll-to-future/styles.css";
176
+
177
+ const config: ScrollToFutureConfig = {
178
+ scrollBar: {
179
+ mode: "both",
180
+ positionMode: "after",
181
+ superimposition: "after",
182
+ boundaryOffset: "4px",
183
+ widthTrack: "8px",
184
+ heightTrack: "98%",
185
+ hideNativeScrollbar: "always",
186
+ },
187
+
188
+ thumb: {
189
+ boundaryOffset: "1px 1px",
190
+ heightTrack: "auto",
191
+ },
192
+
193
+ nativeOnMobile: true,
194
+ selectTheme: "primary",
195
+ optionsTheme: {},
196
+ };
197
+ ```
198
+
199
+ ```tsx
200
+ <ScrollToFuture {...config} />
201
+ ```
202
+
203
+ ## Component properties
204
+
205
+ | Property | Type | Default | Description |
206
+ | ---------------- | -------------------------------------- | -----------------------: | ------------------------------------------------- |
207
+ | `target` | `React.RefObject<HTMLElement \| null>` | Parent element | Element whose scrolling is controlled |
208
+ | `scrollBar` | `ScrollToFutureScrollBar` | Default scrollbar config | Track and positioning configuration |
209
+ | `thumb` | `ScrollToFutureThumb` | Default thumb config | Thumb size and offset configuration |
210
+ | `selectTheme` | `PresetsThemeType` | `"primary"` | Built-in theme name |
211
+ | `optionsTheme` | `ScrollToFutureThemeProps` | `{}` | Custom theme overrides |
212
+ | `nativeOnMobile` | `boolean` | `true` | Use native scrolling on mobile-only input devices |
213
+
214
+ ## Scrollbar configuration
215
+
216
+ ### `mode`
217
+
218
+ Controls which scrollbars are rendered.
219
+
220
+ ```ts
221
+ type ScrollBarMode = "horizontal" | "vertical" | "both";
222
+ ```
223
+
224
+ ```tsx
225
+ <ScrollToFuture
226
+ scrollBar={{
227
+ mode: "vertical",
228
+ }}
229
+ />
230
+ ```
231
+
232
+ Default:
233
+
234
+ ```ts
235
+ "both"
236
+ ```
237
+
238
+ ### `positionMode`
239
+
240
+ Controls the side on which the custom scrollbar is rendered.
241
+
242
+ ```ts
243
+ type PositionMode = "before" | "after";
244
+ ```
245
+
246
+ For a vertical scrollbar:
247
+
248
+ * `"before"` places the track on the left.
249
+ * `"after"` places the track on the right.
250
+
251
+ For a horizontal scrollbar:
252
+
253
+ * `"before"` places the track at the top.
254
+ * `"after"` places the track at the bottom.
255
+
256
+ ```tsx
257
+ <ScrollToFuture
258
+ scrollBar={{
259
+ positionMode: "before",
260
+ }}
261
+ />
262
+ ```
263
+
264
+ Default:
265
+
266
+ ```ts
267
+ "after"
268
+ ```
269
+
270
+ ### `superimposition`
271
+
272
+ Controls whether the scrollbar overlaps the content or reserves space for itself.
273
+
274
+ ```ts
275
+ type Superimposition = "over" | "after";
276
+ ```
277
+
278
+ #### Overlay mode
279
+
280
+ The scrollbar is placed over the content.
281
+
282
+ ```tsx
283
+ <ScrollToFuture
284
+ scrollBar={{
285
+ superimposition: "over",
286
+ }}
287
+ />
288
+ ```
289
+
290
+ #### Reserved-space mode
291
+
292
+ The component adds padding to the target element so the scrollbar does not cover its content.
293
+
294
+ ```tsx
295
+ <ScrollToFuture
296
+ scrollBar={{
297
+ superimposition: "after",
298
+ }}
299
+ />
300
+ ```
301
+
302
+ Default:
303
+
304
+ ```ts
305
+ "after"
306
+ ```
307
+
308
+ ### `boundaryOffset`
309
+
310
+ Sets the outer offset of the track.
311
+
312
+ Accepted values:
313
+
314
+ ```ts
315
+ type BoundaryOffset =
316
+ | `${number}px`
317
+ | `${number}px ${number}px`;
318
+ ```
319
+
320
+ A single value applies the same offset to both sides:
321
+
322
+ ```tsx
323
+ <ScrollToFuture
324
+ scrollBar={{
325
+ boundaryOffset: "6px",
326
+ }}
327
+ />
328
+ ```
329
+
330
+ Two values define the start and end offsets:
331
+
332
+ ```tsx
333
+ <ScrollToFuture
334
+ scrollBar={{
335
+ boundaryOffset: "4px 8px",
336
+ }}
337
+ />
338
+ ```
339
+
340
+ Default:
341
+
342
+ ```ts
343
+ "4px"
344
+ ```
345
+
346
+ ### `widthTrack`
347
+
348
+ Sets the scrollbar track thickness.
349
+
350
+ ```tsx
351
+ <ScrollToFuture
352
+ scrollBar={{
353
+ widthTrack: "10px",
354
+ }}
355
+ />
356
+ ```
357
+
358
+ Accepted value:
359
+
360
+ ```ts
361
+ `${number}px`
362
+ ```
363
+
364
+ The effective default thickness is `8px`.
365
+
366
+ ### `heightTrack`
367
+
368
+ Sets the length of the scrollbar track.
369
+
370
+ Accepted values:
371
+
372
+ ```ts
373
+ type HeightTrackType =
374
+ | `${number}px`
375
+ | `${number}%`
376
+ | `${number}vh`
377
+ | `${number}dvh`
378
+ | `${number}dsvh`;
379
+ ```
380
+
381
+ Examples:
382
+
383
+ ```tsx
384
+ <ScrollToFuture
385
+ scrollBar={{
386
+ heightTrack: "80%",
387
+ }}
388
+ />
389
+ ```
390
+
391
+ ```tsx
392
+ <ScrollToFuture
393
+ scrollBar={{
394
+ heightTrack: "240px",
395
+ }}
396
+ />
397
+ ```
398
+
399
+ ```tsx
400
+ <ScrollToFuture
401
+ scrollBar={{
402
+ heightTrack: "80dvh",
403
+ }}
404
+ />
405
+ ```
406
+
407
+ Default:
408
+
409
+ ```ts
410
+ "98%"
411
+ ```
412
+
413
+ ### `hideNativeScrollbar`
414
+
415
+ Controls when the browser's native scrollbar is hidden.
416
+
417
+ ```ts
418
+ type HideNativeScrollbarMode =
419
+ | false
420
+ | "fine-pointer"
421
+ | "always";
422
+ ```
423
+
424
+ #### Do not hide the native scrollbar
425
+
426
+ ```tsx
427
+ <ScrollToFuture
428
+ scrollBar={{
429
+ hideNativeScrollbar: false,
430
+ }}
431
+ />
432
+ ```
433
+
434
+ #### Hide only when a fine pointer is available
435
+
436
+ This normally applies to devices with a mouse, trackpad, stylus, or another precise pointer.
437
+
438
+ ```tsx
439
+ <ScrollToFuture
440
+ scrollBar={{
441
+ hideNativeScrollbar: "fine-pointer",
442
+ }}
443
+ />
444
+ ```
445
+
446
+ #### Always hide the native scrollbar
447
+
448
+ ```tsx
449
+ <ScrollToFuture
450
+ scrollBar={{
451
+ hideNativeScrollbar: "always",
452
+ }}
453
+ />
454
+ ```
455
+
456
+ Default:
457
+
458
+ ```ts
459
+ "always"
460
+ ```
461
+
462
+ The native scrollbar is hidden only when the custom component covers every currently scrollable axis.
463
+
464
+ For example, when the target can scroll both horizontally and vertically but `mode` is set to `"vertical"`, the native scrollbar is preserved because the horizontal axis is not covered by the custom scrollbar.
465
+
466
+ ## Thumb configuration
467
+
468
+ ### `boundaryOffset`
469
+
470
+ Controls the space between the thumb and the track boundaries.
471
+
472
+ ```tsx
473
+ <ScrollToFuture
474
+ thumb={{
475
+ boundaryOffset: "2px",
476
+ }}
477
+ />
478
+ ```
479
+
480
+ ```tsx
481
+ <ScrollToFuture
482
+ thumb={{
483
+ boundaryOffset: "2px 4px",
484
+ }}
485
+ />
486
+ ```
487
+
488
+ Default:
489
+
490
+ ```ts
491
+ "1px 1px"
492
+ ```
493
+
494
+ ### `heightTrack`
495
+
496
+ Controls the thumb size.
497
+
498
+ ```ts
499
+ type ThumbHeight =
500
+ | "auto"
501
+ | `${number}px`
502
+ | `${number}%`;
503
+ ```
504
+
505
+ #### Automatic size
506
+
507
+ The thumb size is calculated from the ratio between the visible area and the full scrollable content.
508
+
509
+ ```tsx
510
+ <ScrollToFuture
511
+ thumb={{
512
+ heightTrack: "auto",
513
+ }}
514
+ />
515
+ ```
516
+
517
+ #### Fixed size
518
+
519
+ ```tsx
520
+ <ScrollToFuture
521
+ thumb={{
522
+ heightTrack: "48px",
523
+ }}
524
+ />
525
+ ```
526
+
527
+ #### Percentage size
528
+
529
+ ```tsx
530
+ <ScrollToFuture
531
+ thumb={{
532
+ heightTrack: "20%",
533
+ }}
534
+ />
535
+ ```
536
+
537
+ Default:
538
+
539
+ ```ts
540
+ "auto"
541
+ ```
542
+
543
+ The calculated thumb size is constrained to prevent it from becoming too small or occupying the entire track.
544
+
545
+ ## Mobile behavior
546
+
547
+ By default, mobile-only input devices use the browser's native scrolling behavior.
548
+
549
+ ```tsx
550
+ <ScrollToFuture nativeOnMobile />
551
+ ```
552
+
553
+ This is equivalent to:
554
+
555
+ ```tsx
556
+ <ScrollToFuture nativeOnMobile={true} />
557
+ ```
558
+
559
+ On a device whose primary input is coarse and which has no fine pointer:
560
+
561
+ * The custom scrollbar is not rendered.
562
+ * The browser's native scrollbar is not hidden.
563
+ * Native touch scrolling remains available.
564
+
565
+ To force the custom scrollbar to render on mobile devices:
566
+
567
+ ```tsx
568
+ <ScrollToFuture nativeOnMobile={false} />
569
+ ```
570
+
571
+ ## Built-in themes
572
+
573
+ The package includes the following presets:
574
+
575
+ ```ts
576
+ type PresetsThemeType =
577
+ | "primary"
578
+ | "midnight"
579
+ | "neonCyan"
580
+ | "ocean"
581
+ | "deepSea"
582
+ | "forest"
583
+ | "moss"
584
+ | "lava"
585
+ | "ember"
586
+ | "gold"
587
+ | "roseQuartz"
588
+ | "violet"
589
+ | "royal"
590
+ | "arctic"
591
+ | "glass"
592
+ | "graphite"
593
+ | "terminal"
594
+ | "toxic"
595
+ | "candy"
596
+ | "sand"
597
+ | "monoLight"
598
+ | "monoDark";
599
+ ```
600
+
601
+ Select a theme with `selectTheme`:
602
+
603
+ ```tsx
604
+ <ScrollToFuture selectTheme="neonCyan" />
605
+ ```
606
+
607
+ ```tsx
608
+ <ScrollToFuture selectTheme="forest" />
609
+ ```
610
+
611
+ ```tsx
612
+ <ScrollToFuture selectTheme="monoDark" />
613
+ ```
614
+
615
+ ## Custom theme
616
+
617
+ Use `optionsTheme` to override part or all of the selected preset.
618
+
619
+ ```tsx
620
+ <ScrollToFuture
621
+ selectTheme="primary"
622
+ optionsTheme={{
623
+ scrollBar: {
624
+ inactive: {
625
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
626
+ borderRadius: "999px",
627
+ },
628
+
629
+ hover: {
630
+ backgroundColor: "rgba(255, 255, 255, 0.16)",
631
+ },
632
+
633
+ active: {
634
+ backgroundColor: "rgba(255, 255, 255, 0.24)",
635
+ },
636
+ },
637
+
638
+ thumb: {
639
+ inactive: {
640
+ backgroundColor: "#8b5cf6",
641
+ borderRadius: "999px",
642
+ },
643
+
644
+ hover: {
645
+ backgroundColor: "#a78bfa",
646
+ transform: "scale(1.05)",
647
+ },
648
+
649
+ active: {
650
+ backgroundColor: "#ddd6fe",
651
+ transform: "scale(1.12)",
652
+ },
653
+ },
654
+ }}
655
+ />
656
+ ```
657
+
658
+ Custom theme values are deeply merged with the selected preset. You only need to provide the properties you want to replace.
659
+
660
+ ## Theme types
661
+
662
+ ```ts
663
+ type ScrollToFutureThemeProps = {
664
+ scrollBar?: StatusElementsTheme;
665
+ thumb?: StatusElementsTheme;
666
+ };
667
+
668
+ type StatusElementsTheme = {
669
+ inactive?: ScrollToFutureGeneralTypes;
670
+ hover?: ScrollToFutureGeneralTypes;
671
+ active?: ScrollToFutureGeneralTypes;
672
+ };
673
+
674
+ type ScrollToFutureGeneralTypes = {
675
+ backgroundColor?: string;
676
+ opacity?: number;
677
+ border?: string;
678
+ borderRadius?: string;
679
+ outline?: string;
680
+ boxShadow?: string;
681
+ transition?: string;
682
+ transform?: string;
683
+ };
684
+ ```
685
+
686
+ ## Complete customization example
687
+
688
+ ```tsx
689
+ import { useRef } from "react";
690
+ import { ScrollToFuture } from "scroll-to-future";
691
+
692
+ export const CustomScrollbarExample = () => {
693
+ const targetRef = useRef<HTMLDivElement>(null);
694
+
695
+ return (
696
+ <div style={{ position: "relative" }}>
697
+ <div
698
+ ref={targetRef}
699
+ style={{
700
+ width: "600px",
701
+ height: "400px",
702
+ overflow: "auto",
703
+ }}
704
+ >
705
+ <div
706
+ style={{
707
+ width: "1200px",
708
+ minHeight: "1400px",
709
+ padding: "24px",
710
+ }}
711
+ >
712
+ Scrollable content
713
+ </div>
714
+ </div>
715
+
716
+ <ScrollToFuture
717
+ target={targetRef}
718
+ nativeOnMobile={true}
719
+ selectTheme="violet"
720
+ scrollBar={{
721
+ mode: "both",
722
+ positionMode: "after",
723
+ superimposition: "over",
724
+ boundaryOffset: "6px",
725
+ widthTrack: "10px",
726
+ heightTrack: "90%",
727
+ hideNativeScrollbar: "fine-pointer",
728
+ }}
729
+ thumb={{
730
+ boundaryOffset: "2px",
731
+ heightTrack: "auto",
732
+ }}
733
+ optionsTheme={{
734
+ thumb: {
735
+ active: {
736
+ transform: "scale(1.15)",
737
+ boxShadow: "0 0 16px rgba(139, 92, 246, 0.8)",
738
+ },
739
+ },
740
+ }}
741
+ />
742
+ </div>
743
+ );
744
+ };
745
+ ```
746
+
747
+ ## Next.js
748
+
749
+ The component uses browser APIs and must be rendered inside a Client Component.
750
+
751
+ ```tsx
752
+ "use client";
753
+
754
+ import { ScrollToFuture } from "scroll-to-future";
755
+
756
+ export const ScrollContainer = ({
757
+ children,
758
+ }: {
759
+ children: React.ReactNode;
760
+ }) => {
761
+ return (
762
+ <div
763
+ style={{
764
+ position: "relative",
765
+ height: "100dvh",
766
+ overflow: "auto",
767
+ }}
768
+ >
769
+ <ScrollToFuture />
770
+
771
+ {children}
772
+ </div>
773
+ );
774
+ };
775
+ ```
776
+
777
+ ## How it works
778
+
779
+ The component observes the target element and its content using browser observers.
780
+
781
+ It automatically recalculates:
782
+
783
+ * Scrollable width and height
784
+ * Current scroll position
785
+ * Visible container size
786
+ * Track dimensions
787
+ * Thumb dimensions
788
+ * Thumb position
789
+ * Target element position
790
+ * Horizontal and vertical overflow availability
791
+
792
+ The scrollbar is updated when:
793
+
794
+ * The target is scrolled
795
+ * The window is resized
796
+ * The visual viewport changes
797
+ * The target changes size
798
+ * Child elements change size
799
+ * Elements are added or removed
800
+ * Relevant styles or classes change
801
+
802
+ ## Interaction
803
+
804
+ ### Dragging the thumb
805
+
806
+ Press and drag the thumb to change the target's scroll position.
807
+
808
+ Pointer capture is used during dragging, so the interaction continues even when the pointer leaves the thumb.
809
+
810
+ ### Clicking the track
811
+
812
+ Click an empty part of the track to move the thumb toward that position.
813
+
814
+ The requested scroll position is automatically clamped to the available scroll range.
815
+
816
+ ## Page scrolling
817
+
818
+ The component supports page scroll targets such as:
819
+
820
+ * `document.body`
821
+ * `document.documentElement`
822
+ * `document.scrollingElement`
823
+
824
+ When the target is part of the document scrolling system, the component resolves the active scroll container and uses the browser viewport for its measurements.
825
+
826
+ ## Important CSS requirements
827
+
828
+ The target element should normally have:
829
+
830
+ ```css
831
+ .scroll-container {
832
+ position: relative;
833
+ overflow: auto;
834
+ width: 100%;
835
+ height: 400px;
836
+ }
837
+ ```
838
+
839
+ A scrollbar cannot appear when the element has no constrained size or when its content does not exceed its visible area.
840
+
841
+ For vertical scrolling:
842
+
843
+ ```css
844
+ .scroll-container {
845
+ overflow-y: auto;
846
+ }
847
+ ```
848
+
849
+ For horizontal scrolling:
850
+
851
+ ```css
852
+ .scroll-container {
853
+ overflow-x: auto;
854
+ }
855
+ ```
856
+
857
+ For both axes:
858
+
859
+ ```css
860
+ .scroll-container {
861
+ overflow: auto;
862
+ }
863
+ ```
864
+
865
+ ## Troubleshooting
866
+
867
+ ### The custom scrollbar is not visible
868
+
869
+ Check that:
870
+
871
+ 1. The target has a constrained width or height.
872
+ 2. The content is larger than the target.
873
+ 3. The target uses `overflow: auto` or `overflow: scroll`.
874
+ 4. The selected `mode` includes the overflowing axis.
875
+ 5. The component is rendered in a Client Component.
876
+ 6. `nativeOnMobile` is not disabling the custom scrollbar on the current device.
877
+
878
+ ### The browser scrollbar is still visible
879
+
880
+ Check the following:
881
+
882
+ 1. `hideNativeScrollbar` is not `false`.
883
+ 2. The custom component covers every scrollable axis.
884
+ 3. The correct element is passed through `target`.
885
+ 4. The actual scroll container is not a nested child of the supplied target.
886
+ 5. `nativeOnMobile` is not preserving native scrolling on the current device.
887
+ 6. `"fine-pointer"` is only active when the device has a fine pointer.
888
+
889
+ To force native scrollbar hiding on desktop and mobile:
890
+
891
+ ```tsx
892
+ <ScrollToFuture
893
+ nativeOnMobile={false}
894
+ scrollBar={{
895
+ hideNativeScrollbar: "always",
896
+ }}
897
+ />
898
+ ```
899
+
900
+ ### The content moves when the scrollbar appears
901
+
902
+ The default `superimposition` value is `"after"`, which reserves space by adding padding to the target.
903
+
904
+ Use overlay mode when the scrollbar should not affect content spacing:
905
+
906
+ ```tsx
907
+ <ScrollToFuture
908
+ scrollBar={{
909
+ superimposition: "over",
910
+ }}
911
+ />
912
+ ```
913
+
914
+ ### The scrollbar is rendered on the wrong element
915
+
916
+ Pass an explicit ref:
917
+
918
+ ```tsx
919
+ const targetRef = useRef<HTMLDivElement>(null);
920
+
921
+ <div ref={targetRef}>...</div>
922
+
923
+ <ScrollToFuture target={targetRef} />
924
+ ```
925
+
926
+ ## Browser requirements
927
+
928
+ The component relies on modern browser APIs:
929
+
930
+ * `ResizeObserver`
931
+ * `MutationObserver`
932
+ * Pointer Events
933
+ * `requestAnimationFrame`
934
+ * `matchMedia`
935
+ * CSS custom properties
936
+
937
+ For older browsers, additional polyfills may be required.
938
+
939
+ ## TypeScript
940
+
941
+ The package exports the component and its public configuration type:
942
+
943
+ ```ts
944
+ export { ScrollToFuture } from "scroll-to-future";
945
+
946
+ export type {
947
+ ScrollToFutureConfig,
948
+ } from "scroll-to-future";
949
+ ```
950
+
951
+ Example:
952
+
953
+ ```tsx
954
+ import type { ScrollToFutureConfig } from "scroll-to-future";
955
+
956
+ const scrollbarConfig: ScrollToFutureConfig = {
957
+ selectTheme: "graphite",
958
+
959
+ scrollBar: {
960
+ mode: "vertical",
961
+ positionMode: "after",
962
+ superimposition: "over",
963
+ hideNativeScrollbar: "always",
964
+ },
965
+
966
+ thumb: {
967
+ heightTrack: "auto",
968
+ },
969
+ };
970
+ ```