What is the shadcn scroll-fade utility and how do you use it?

Learn how to use the shadcn scroll-fade utility to add scroll-aware edge fades to any container. Full class reference, examples, and tips.

AshFull-stack developer and UI/UX enthusiast.
Published Jun 28, 2026
Updated Jun 28, 2026
12 min read
shadcn/uiTailwind CSSUtilitiesNext.jsTypeScript
shadcn scroll-fade utility guide cover image

The shadcn scroll-fade utility adds scroll-aware edge fades to any scroll container using a single Tailwind class. It shipped in June 2026 as part of the shadcn/ui chat interface release. The fade uses mask-image — so it dissolves the content itself rather than overlaying a colour — and adapts to any background without configuration. Projects initialised with npx shadcn@latest init already have it.

scroll-fade is one of many utilities and primitives in our shadcn components directory — and you can match it to your theme in the editor.

How does shadcn scroll-fade work under the hood?

scroll-fade applies a CSS mask-image that tracks scroll position via animation-timeline: scroll(self y). No JavaScript runs. No scroll listeners fire. The fade is purely CSS-driven, which means zero runtime cost and predictable output across all supported browsers.

The scroll behaviour has three states:

  • At rest — the top edge is crisp, the bottom edge fades to signal more content below.
  • Mid-scroll — both the top and bottom edges fade simultaneously.
  • At the end — the bottom edge sharpens to confirm the last item is visible.

The default fade depth is 12% of the container height, capped at 40px. This keeps tall scroll containers subtle without any extra configuration.

No JavaScript, no listeners. scroll-fade uses the scroll-driven animations API. The browser handles position tracking natively. Zero runtime cost.

How to install the shadcn scroll-fade utility

If you initialised your project with npx shadcn@latest init, you already have scroll-fade. It ships with the shadcn package and the CLI imports it automatically into your global CSS file. There is nothing else to do.

For projects set up without the CLI, install the package manually:

bash

Then import the shared utilities in your global CSS file:

globals.css

That is the entire installation. There is no component to register and no components.json entry to add.

No CLI add command. scroll-fade is a CSS utility, not a component. Running shadcn add scroll-fade is not needed and will not work. The utility loads automatically via shadcn/tailwind.css.

Full shadcn scroll-fade class reference

The utility ships 13 Tailwind utility classes. Each targets a specific scroll axis or edge.

ClassAxisWhat it does
scroll-fadeY — verticalFades top and bottom edges. Tracks vertical scroll position.
scroll-fade-yY — verticalIdentical to scroll-fade. Explicit vertical axis variant.
scroll-fade-xX — horizontalFades left and right edges. Tracks horizontal scroll position.
scroll-fade-tY — top onlyFades the top edge only.
scroll-fade-bY — bottom onlyFades the bottom edge only.
scroll-fade-lX — left onlyFades the left edge. Physical — does not mirror in RTL.
scroll-fade-rX — right onlyFades the right edge. Physical — does not mirror in RTL.
scroll-fade-sX — start edgeFades the inline-start edge. Mirrors automatically in RTL.
scroll-fade-eX — end edgeFades the inline-end edge. Mirrors automatically in RTL.
scroll-fade-<number>Size modifierSets fade depth on spacing scale. scroll-fade-8 = 32px.
scroll-fade-[<value>]Arbitrary sizeSets any custom depth. scroll-fade-[60px].
scroll-fade-{t,b,s,e}-<number>Per-edge sizeSets depth on one edge only. scroll-fade-b-8.
scroll-fade-noneDisableRemoves the fade mask entirely.

Apply the class to the element that has overflow-y-auto or overflow-x-autonot to a wrapper around it.

Vertical list with scroll-fade

Dashboard
Analytics
Reports
Team Members
Settings
Billing
Integrations
API Keys
Webhooks
Notifications
Security
Audit Log
Help & Support
Documentation

Horizontal tags with scroll-fade-x

ReactNext.jsTypeScriptTailwind CSSshadcn/uiRadix UIFramer MotionZustandTanStack QueryPrismatRPCZodVitestPlaywright

When to use each shadcn scroll-fade variant

Use the right variant for your scroll axis. The wrong class on the wrong axis produces no visible output.

Use scroll-fade or scroll-fade-y on any vertically scrolling list. Good candidates include sidebar navigation, command palettes, dropdown menus, and long content feeds. Long dropdowns get the same treatment — the shadcn select component is a natural place to apply it. Sidebar navigation is one of the most common vertical list patterns in production apps. If you are building a collapsible sidebar, see our guide on the shadcn resizable sidebar component for the full implementation pattern.

Use scroll-fade-x on horizontal containers like tag rows, chip selectors, and horizontal feature lists. The horizontal fade is direction-aware. In RTL layouts, the crisp edge and fade follow the reading direction automatically — no extra classes needed.

Use edge-specific variants when only one boundary matters. For example, use scroll-fade-b on a top-loaded feed so only the bottom edge fades to signal more content. Use scroll-fade-t on a bottom-anchored chat thread to signal history above.

Use scroll-fade-s and scroll-fade-e instead of scroll-fade-l and scroll-fade-r when building RTL-compatible layouts. The logical variants mirror automatically. The physical variants (l and r) stay fixed regardless of text direction.

How to use shadcn scroll-fade with ScrollArea and MessageScroller

scroll-fade works on any element with overflow. However, two shadcn/ui components pair with it directly in production: ScrollArea and MessageScroller.

Common mistake — apply to the inner viewport, not the outer wrapper. The outer wrapper holds the border and background. Placing scroll-fade on it dissolves the card edge instead of the content.

1Introduction
2Getting Started
3Installation
4Project Structure
5Configuration
6Components
7Styling
8Theming
9Dark Mode
10Typography
11Layouts
12Forms
13Data Tables
14Authentication
15API Routes
16Deployment
17Testing
18Performance
19Accessibility
20Changelog

The content fades at the edges. Border stays crisp.

With MessageScroller:

MessageScroller is the scroll container by design. Apply scroll-fade directly to it — no inner wrapper needed.

MessageScroller + scroll-fade
Welcome! How can I help you today?
I need help setting up scroll-fade on a chat.
Use scroll-fade directly on MessageScroller. It is the scroll container by design.
Do I need an inner wrapper?
No. Unlike ScrollArea, MessageScroller owns the overflow itself. Just add the class directly.
What about streaming replies?
The bottom edge fades while streaming, then sharpens when the stream ends and there is nothing more to show.

This is the most common production use case for the shadcn fade effect. Chat interfaces with streaming replies benefit most. The bottom edge fades while the user reads, then sharpens when there is nothing more to show. For full chat implementation patterns including message bubbles and typing indicators, see our shadcn chat UI guide.

How to control the shadcn scroll-fade depth

The default fade depth is 12% of the container height, capped at 40px. For most containers this requires no adjustment. However, two situations call for a custom size.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20

scroll-fade — 12% of height, capped at 40px

You can also target individual edges with size modifiers. scroll-fade-b-8 sets only the bottom fade depth to 32px while leaving the top edge at its default. This is useful when the top of a list always starts flush and only the bottom needs a fade cue.

Does shadcn scroll-fade show a fade when content does not overflow?

No. If the content fits within the container without scrolling, no fade appears. You can therefore apply scroll-fade to every list in your app defensively — without checking whether each one actually overflows. The utility handles the conditional logic in CSS with no JavaScript detection needed.

scroll-fade applied to both
Dashboard
Settings
Profile

Content fits — no fade shown. Safe to apply unconditionally.

This removes the need for useRef plus useEffect scroll detection that developers previously wrote to conditionally render gradient overlays. One class handles both the overflowing and non-overflowing cases correctly.

shadcn scroll-fade vs a CSS gradient overlay: what is the difference?

Before scroll-fade, the standard approach was an absolutely positioned div with a gradient background colour that matched the container. That pattern has three problems: it breaks on non-solid backgrounds, it is always visible regardless of scroll position, and it requires manual RTL adjustments.

ApproachBackground-independentScroll-awareZero JSRTL support
CSS gradient overlayMust match backgroundAlways visibleYesManual
JS scroll listener + overlayMust match backgroundYesNoManual
scroll-fade utilityUses mask-imageCSS scroll timelineYesLogical variants

The gradient overlay approach breaks on non-solid backgrounds — glassmorphism panels, images behind cards, and dark mode transitions all require separate gradient colour values per context. scroll-fade uses mask-image instead. It dissolves the content itself, so it adapts to any background with no configuration.

The JS scroll listener approach adds runtime cost and can cause layout thrash on heavy lists. scroll-fade has zero runtime cost. It is entirely CSS-driven via the scroll-driven animations API, so the browser handles position tracking natively.

A sidebar nav list is the most common vertical scroll pattern in production apps. Nav items overflow when a project has many routes — settings panels, admin dashboards, and docs sites all hit this. scroll-fade signals overflowing items without adding a scrollbar that breaks the sidebar's visual edge.

Apply scroll-fade directly to the scrollable nav container. Keep the sidebar wrapper clean — border, background, and fixed height live on the outer element. The fade dissolves the nav items themselves.

Fixed header and footer, scrollable middle. Structure the sidebar as a flex column with h-screen. The header and footer are fixed. Only the middle <nav> gets flex-1 overflow-y-auto and scroll-fade. This is the correct pattern for any app shell sidebar.

If the nav items fit without overflowing, no fade appears — safe to apply unconditionally. For the full sidebar implementation with collapsible groups and resize handles, see the collapsible sidebar pattern.

How to use shadcn scroll-fade in a command palette

A command palette (built with the shadcn Command component) shows a filtered results list that can grow to any length. Without a fade, the list either clips abruptly at a hard height or forces a visible scrollbar that looks out of place inside a floating panel.

scroll-fade dissolves the bottom of the list naturally, signalling more results without breaking the panel's visual container.

Pages

Dashboard
Analytics
Reports
Team
Settings
Billing

Actions

Create Project
Invite Member
Generate API Key
Export Data
Import Data

Help

Documentation
Support
Changelog
Status Page

Apply to CommandList, not Command. CommandList is the scroll container. Command is the outer wrapper that holds the input and the list together. Applying scroll-fade to the outer Command wraps the input field in the fade — which is wrong. Apply it to CommandList only.

The max-h-80 cap keeps the palette compact. As the user types and filters results, the list height adjusts and the fade appears only when results overflow the cap.

How to use shadcn scroll-fade in a chat thread

A chat thread is the canonical use case scroll-fade shipped for. The thread anchors to the bottom while streaming. History accumulates above. scroll-fade-t fades the top edge to signal history above — while leaving the bottom edge crisp, because the live reply is what the user is reading.

Chat
Hey, can you help me with the scroll-fade utility?
Of course! scroll-fade adds CSS mask-image fades to scroll containers. What do you need help with?
How do I apply it to a sidebar nav?
Add scroll-fade to the element with overflow-y-auto. Keep the outer wrapper clean — border and background go on the parent.
Does it work on horizontal containers too?
Yes! Use scroll-fade-x for horizontal scrolling. It is RTL-aware — the fade direction mirrors automatically.
What about when content does not overflow?
No fade appears. You can apply it defensively to every list without checking overflow. The CSS handles it.

Use scroll-fade-t, not scroll-fade. scroll-fade fades both edges. In a chat thread the bottom edge should always be crisp — it is the live reply the user is watching. scroll-fade-t fades the top edge only, signalling history above while keeping the active reply fully visible at the bottom.

The fade disappears when the thread is scrolled to the very top, because there is no hidden history above. It reappears as the user scrolls down and history accumulates above the viewport. For the complete chat implementation with typing indicators, timestamps, and file attachments, see our shadcn chat UI examples.

Horizontal chip rows and tag selectors overflow on narrow viewports and inside constrained containers like card sidebars and filter bars. A scrollbar on a chip row looks wrong — it is too heavy for the visual weight of the element. scroll-fade-x hints at overflow without a scrollbar.

Selected: React, Next.js

shrink-0 on every chip, pb-1 on the container. Without shrink-0, flex children compress instead of overflowing. The pb-1 bottom padding prevents the scrollbar (on systems that show one) from clipping the chip border. Neither affects the scroll-fade-x behaviour.

This pattern works identically for horizontal nav tabs, breadcrumb rows, and step indicators in multi-step forms. The fade is RTL-aware — on RTL layouts the crisp edge automatically shifts to the right and the fade appears on the left, with no extra classes.

A modal with a long list — search results, team member selectors, notification feeds — needs scroll handling that does not fight the modal's own overflow. The standard mistake is applying overflow to the DialogContent itself, which breaks focus trapping and the close animation.

The correct pattern: fixed-height content area inside the dialog, with scroll-fade on that inner container only.

Add team members

Do not put overflow-y-auto on DialogContent. Radix Dialog manages its own overflow for focus trapping and scroll locking. Adding overflow-y-auto to DialogContent breaks both. Instead, use max-h-[85vh] flex flex-col on DialogContent, then put ScrollArea + scroll-fade on the inner list only.

The max-h-[85vh] cap on DialogContent keeps the modal off the viewport edges on short screens. The flex-1 on ScrollArea lets the list fill whatever space remains between the fixed header and footer.

Frequently asked questions about shadcn scroll-fade

Build faster with shadcn/ui templates

Utilities like scroll-fade are most useful when the rest of your UI is already in good shape. If you are building a landing page or SaaS product and want a production-ready starting point built on Next.js App Router, Tailwind CSS, and TypeScript, browse the shadcn/ui landing page templates at ShadcnDeck. Every template uses shadcn/ui natively, so utilities like scroll-fade drop straight in without any compatibility work. Free templates with full source code are also available — no attribution required.

Launch your SaaS faster with a modern Shadcn UI template - Explore Free Templates
A
Ash

Full-stack developer and UI/UX enthusiast.

Related Articles