Command Palette

Search for a command to run...

Loading component...

Components Free Scroll with fade effect

Scroll with fade effect

A top/bottom scrollable fade effect that creates smooth visual transitions at the top and bottom edges. And the best part is it doesn't use any JS or functions, just simple pure CSS animation.

Dependencies

Interaction Type

Scroll to see the fade effect
Watch the smooth fade transitions
Lightweight css only animation
npx shadcn add @skiper-ui/skiper87

Under the hood

It's a simple animation timeline using CSS. The CSS class below is by Gustav Ekerot and slightly tweaked by me.

Update global.css

/* Scroll Fade Effect */
@supports (animation-timeline: scroll()) {
  @property --ft {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
  }

  @property --fb {
    syntax: "<length>";
    inherits: false;
    initial-value: 40px;
  }

  .scroll-fade-y,
  [data-slot="scroll-area-viewport"] {
    --ft: 0px;
    --fb: 40px;
    mask-image: linear-gradient(
      to bottom,
      transparent 0,
      #000 var(--ft),
      #000 calc(100% - var(--fb)),
      transparent 100%
    );
    mask-size: 100% 100%;
    mask-repeat: no-repeat;
    animation:
      fadeTop 1 linear both,
      fadeBottom 1 linear both;
    animation-timeline: scroll(self), scroll(self);
    animation-range:
      0% 12%,
      88% 100%;
  }

  @keyframes fadeTop {
    from {
      --ft: 0px;
    }
    to {
      --ft: 40px;
    }
  }

  @keyframes fadeBottom {
    from {
      --fb: 40px;
    }
    to {
      --fb: 0px;
    }
  }
}

How to implement

import React from "react";

const Skiper87 = () => {
  return (
    <div className="rounded-xl border">
      <div className="scroll-fade-y w-62 h-72 overflow-scroll rounded-xl">
        <div className="space-y-1 p-1">
          {Array.from({ length: 11 }).map((_, index) => (
            <div
              key={index}
              className="text-foreground/30 bg-foreground/5 flex h-10 w-full items-center gap-2 rounded-lg px-4"
            >
              00{index} <div className="bg-foreground/10 h-px flex-1"></div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export { Skiper87 };

How to implement with scroll area

<div className="rounded-xl border">
  <ScrollArea className="w-62 h-72 rounded-xl">
    <div className="space-y-1 p-1">
      {Array.from({ length: 11 }).map((_, index) => (
        <div
          key={index}
          className="text-foreground/30 hover:bg-foreground/10 bg-foreground/5 flex h-10 w-full items-center gap-2 rounded-lg px-4"
        >
          00{index} <div className="bg-foreground/10 h-px flex-1"></div>
        </div>
      ))}
    </div>
  </ScrollArea>
</div>

But wait, we didn't add the fade class here - how come it's working? In our global CSS, we added [data-slot="scroll-area-viewport"] in global.css which automatically applies the fade effect to the ScrollArea component. Alternatively, you can update the ScrollArea viewport and add the scroll-fade-y class there.

Attribution

Source code

Click on the top right
to view the source code

Keep in mind

Most components here are recreations of the best out there. I don't claim to be the original creator. This is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone, but if I missed something, let me know.

Contact

Additionlly, if you find any bug or issue, feel free to
Drop a dm.

License & Usage:

  • Free to use and modify in both personal and commercial projects.
  • Attribution to Skiper UI is required when using the free version.
  • No attribution required with Skiper UI Pro.