shadcn.io is not affiliated with official shadcn/ui
The edge with more content behind it fades out, and the edge you have reached stays crisp. The fade follows the scroll position as you go.
Use it on anything that scrolls: a list in a card, a row of tags, a chat. It is a set of Tailwind CSS utilities, not a component, and it needs no script. These are shadcn/ui's scroll-fade classes, the ones shadcn/tailwind.css ships, with one fix for RTL.
Installation
The command adds the utilities to your global CSS file. A project that imports shadcn/tailwind.css already has them, so skip it there. Components that use the class, such as Attachment and Message Scroller, install it with them.
Usage
<div className="scroll-fade h-72 overflow-y-auto">{/* … */}</div>| Class | What it does |
|---|---|
scroll-fade | Fades the top and bottom edges of a vertical scroller as it scrolls. |
scroll-fade-y | The same as scroll-fade. |
scroll-fade-x | Fades the start and end edges of a horizontal scroller, mirrored in RTL. |
scroll-fade-t | Fades the top edge only. |
scroll-fade-b | Fades the bottom edge only. |
scroll-fade-l | Fades the left edge only. |
scroll-fade-r | Fades the right edge only. |
scroll-fade-s | Fades the start edge only, mirrored in RTL. |
scroll-fade-e | Fades the end edge only, mirrored in RTL. |
scroll-fade-<number> | Sets the fade's depth on the spacing scale. |
scroll-fade-[<value>] | Sets the fade's depth to any length or percentage. |
scroll-fade-{t,b,s,e}-<number> | Sets one edge's depth on the spacing scale. |
scroll-fade-{t,b,s,e}-[<value>] | Sets one edge's depth to any length or percentage. |
scroll-fade-none | Removes the fade, in any class order. |
Put the class on the element that scrolls, the one with overflow-y-auto or overflow-x-auto. At rest the top is crisp and the bottom fades. Mid-scroll both edges fade, and at the end the bottom sharpens. The fade is a mask-image, so it dissolves the content rather than painting a color over it, and it works on any background. In a card, put the border and the background on a wrapper and the class on the scroller inside it, or the card's own edge fades too.
Demos
Overflow
Three items in a scroller with scroll-fade and no fixed height. Nothing overflows, so nothing fades. You can put the class on a list without checking whether it will scroll.
Horizontal
scroll-fade-x on a row of twelve tags with overflow-x-auto. At rest the start edge is crisp and the end edge fades. The fade follows the reading direction, so in RTL the crisp edge is on the right. scroll-fade-<number> and scroll-fade-none work the same on both axes.
Edge
Four scrollers that each fade one edge: scroll-fade-t and scroll-fade-b on lists, scroll-fade-s and scroll-fade-e on rows of tags. A start edge fades in once you scroll away from it, and an end edge fades out when you reach it. Use -l and -r for a physical side, and -s and -e when the side should mirror in RTL.
Size
The same list with scroll-fade-4 and with scroll-fade-24: a 16px fade and a 96px one. The default depth is 12 percent of the container, capped at 40px so a tall scroller stays subtle. scroll-fade-b-8 scroll-fade-t-2 gives each edge its own depth. How far you scroll before a fade is full is --scroll-fade-reveal, 96px by default, so [--scroll-fade-reveal:64px] makes the reveal quicker.
None
The same list with scroll-fade, and with scroll-fade scroll-fade-none. scroll-fade-none removes the mask whatever the class order, so a breakpoint or a state can turn the fade off, such as md:scroll-fade-none.
RTL
Ten Arabic tags in a row with dir="rtl" and scroll-fade-x. The right edge is crisp and the left edge fades, mirrored from LTR, with no extra class. The classes go by the nearest dir attribute, so a dir="ltr" scroller inside an RTL page, such as a code block, keeps its left-to-right fade. shadcn/ui's version mirrors that one too, and fades its wrong side.
FAQ
What happens in a browser without scroll-driven animations?
The fade is static. scroll-fade and scroll-fade-x fade both edges, and an edge class fades its one edge, whatever the scroll position. The scroll-aware version is a CSS scroll-driven animation, so there is no script and no scroll listener in either case.
Why does the scrollbar fade too?
The mask is on the scroll container, and a visible scrollbar is part of it, so its ends fade with the content. Hide the scrollbar with scrollbar-none if the list doesn't need one, as every demo on this page does. Keep it when the scroll position matters to the reader, such as a long log.
Why does my card's border fade?
The class is on the same element as the border or the background. The mask fades everything that element paints. Put the border, the radius and the background on a wrapper with overflow-hidden, and scroll-fade on the scroller inside it, as the demos do.
My project imports shadcn/tailwind.css. Do I need this?
No. shadcn/tailwind.css ships the same scroll-fade utilities, so the classes already work. This install is for a project without that import. With both, nothing breaks, but every scroll-fade rule ends up in your built CSS twice. The command writes its rules after the import, so they win, RTL included.
Can I use scroll-fade with Scroll Area or Message Scroller?
Yes. The class goes on the element that scrolls, which is the viewport in both, not the root. Message Scroller already fades its bottom edge with scroll-fade-b on its viewport. For Scroll Area, add the class to the viewport's classes in the scroll-area file under components/ui.
How do I install scroll-fade in React?
Run the command in the Installation section on this page. It adds the scroll-fade utilities to your global CSS file and no component file. Components that use the class, such as Attachment and Message Scroller, list it as a dependency and install it with them.
API Reference
Scroll Fade
scroll-fadeclassscroll-fade-yclassscroll-fade-xclassscroll-fade-tclassscroll-fade-bclassscroll-fade-lclassscroll-fade-rclassscroll-fade-sclassscroll-fade-eclassscroll-fade-*classscroll-fade-t-*classscroll-fade-b-*classscroll-fade-s-*classscroll-fade-e-*classscroll-fade-noneclass