@c0ffee_39/react-cool-scroll
TypeScript icon, indicating that this package has built-in type declarations

1.0.1 • Public • Published

React-custom-scroll 🚀

Simple, user-friendly, cross-platform and adaptive scrolling. Customize as you want, use a lot of flexible settings and enjoy the pleasant UI/UX of a custom scroll ⚙️✨🎨

Basic usage

Minimal code example

Let's say we render lots of cards inside some parent.

In your component

"use client"; // For NextJS
import classes from "./MyComp.module.scss";
import CustomScroll, { useScrollSetup } from "@c0ffee_39/react-custom-scroll";

export function MyComp() {
  const [ancestorRef, childrenRef, translateX, setTranslateX] = useScrollSetup<
    HTMLDivElement,
    HTMLDivElement
  >();

  return (
    <div className={classes.parentWrapper} ref={ancestorRef}>
      <div
        className={classes.childrenWrapper}
        ref={childrenRef}
        style={{
          transform: `translateX(${translateX}px)`,
        }}
      >
        <Card />
        <Card />
        <Card />
        ...
        <Card />
      </div>
      <CustomScroll
        ancestorRef={ancestorRef.current}
        childrenRef={childrenRef.current}
        scrollLength={100}
        setTranslate={setTranslateX}
      />
    </div>
  );
}

Then, add to parent element overflow: hidden and width: max-content to children

.parentWrapper {
  overflow: hidden;
}
.childrenWrapper {
  width: max-content;
}

Default direction is horizontal. To change this, use direction="vertical" prop. There is no need to change anything else.

Congratulations🥳! You got a beautiful custom scroll with default styles🌟🎨

Default scroll

Explanation

You need to import useScrollSetup hook, adding <Parent_HTML_Element_Type, Children_HTML_Element_Type> to generic (just skip this in pure javascript). Then, import <CustomScroll/> component.

❗️Error

You can place <CustomScroll/> wherever you want, but not inside childrenRef element. Otherwise, you'll end up with endlessly growing recursive errors in the browser console


useScrollSetup returns 4 variables. Hang ancestorRef on your parent element, childrenRef - on scrollable child. translate you must add as

style={{
  transform: `translateX(${translateX}px)`,
}}

to your childrenWrapper.

You need add width: max-content to your childrenRef element because it should be equal to the width of scrollable content

<CustomScroll/> accepts 4 required props - ancestorRef, childrenRef, scrollLength and setTranslate.

ancestorRef, childrenRef and setTranslate are used for under-the-hood logic and must be used as specified.

Sensitivity

Sensitivity is indicated by only one parameter - an essential property scrollLength. It's defined in pixels, and literally mean the length of scroll.

👍Success

Setting scrollLength prop, scrolling speed and sensitivity will adjust to the length automatically

Default behaviour

By default, scroll works like this:

  • Enabled scrolls: wheel, drag, drag the scroll by pressing the left mouse button, swipe in mobile devices. You can disable dragging by drag prop. Other mechanics сan't be disabled
  • Scroll is always visible, you can change this by visible prop
  • cursor: grab on children element, and grabbing while you grab
    • You can safely set any cursor value on childrenElement or inner elements, and it'll work correctly. For example, set cursor: pointer to <Card/> element. Then, between <Card/>s cursor'll be grab, and while dragging cursor'll be grabbing even over <Card/>. You can change this behaviour by drag prop
  • Default scroll styles is like in Styles API Reference. You can change this by styles prop
  • direction="horizontal"

Full customization

<CustomScroll/> can accept option prop children. For example, let's replace our boring scroll to porsche

<CustomScroll
  ancestorRef={ancestorRef.current}
  childrenRef={childrenRef.current}
  scrollLength={276}
  setTranslate={setTranslateX}
  styles={{
    wrapper: {
      transform: "translateY(-40px)", // Unnecessary, added for beauty
    },
  }}
>
  <Image src={PorscheImg} alt="" />
</CustomScroll>

Porsche scroll

You can add any layout as children as you want.

🚧Warning

You still need to pass the required scrollLength prop, and its width must match your layout to work correctly

API

<CustomScroll/>

Props

ancestorRef

ancestorRef prop is taken from useCustomScroll hook and used in under-the-hood logic for binding parentEl to scroll. Must be used only as specified.

childrenRef

childrenRef prop is taken from useCustomScroll hook and used in under-the-hood logic for binding childrenEl to scroll. Must be used only as specified.

setTranslate

setTranslate prop is taken from useCustomScroll hook and used as a callback function for translate updating. Must be used only as specified.

scrollLength

Accepts value in pixels and adjust sensitivity. See Sensitivity section.

direction

Accepts 'horizontal' | 'vertical'. Default is horizontal

visible

Accepts 'visible' | 'onHover' | 'none'. Defaults to visible

  • visible. Scroll is always visible
  • onHover.
    • Desktop. Scroll visible only while hovering on children element
    • Mobile. Scroll visible on touchstart event, while scrolling and disappear after 1 second afrer scroll ending
  • none. Scroll is always invisible, but all mechanics are working

drag

drag prop have a type

type dragType = {
  draggable: boolean;
  showGrabCursor?: boolean;
};

draggable: you can disable draggable mechanic. Default to true.

showGrabCursor: default to true. You can disable cursor: grab while hovering on childrenEl. But, while dragging, cursor: grabbing will still be active.

styles

styles prop have a type

type stylesType = {
  wrapper?: CSSProperties;
  scroll?: CSSProperties;
};

The markup of scroll looks simplistically like this

<>
  <div className={classes.wrapper}>
    <div className={classes.scroll}></div>
  </div>
</>

<div> with scroll class is scroll element itself. <div> with wrapper class is a scroll wrapper, the element within which the scroll moves, and you can freely adjust it.

You can add all styles as you want to this objects.

Default styles

background: transparent for wrapper and

.scroll {
  border-radius: 4px;
  background: #b3b3b3;
  height: 4px;
  width: 4px;
}

for scroll.

children

See Full customization section.

useCustomScroll hook

useCustomScroll hook must take generic - <Parent_HTML_Element_Type, Children_HTML_Element_Type>. In example in Basic usage section it's <HTMLDivElement, HTMLDivElement>

It returns following variables:

ancestorRef

See <CustomScroll/> API section

childrenRef

See <CustomScroll/> API section

translate

translate is reactive (useState) value that used to update transform property on children element, by which scroll effect created. Its updating is completely controlled by the built-in logic, and it should be used only as specified, and in no other way.

Usage

<div
  className={classes.childrenWrapper}
  ref={childrenRef}
  style={{
    transform: `translateX(${translateX}px)`,
  }}
>
  ...
</div>

setTranslate

See <CustomScroll/> API section

Package Sidebar

Install

npm i @c0ffee_39/react-cool-scroll

Weekly Downloads

0

Version

1.0.1

License

MIT

Unpacked Size

753 kB

Total Files

13

Last publish

Collaborators

  • c0ffee_39