Create cn helper utility function
Create lib/utils.ts with a cn helper function that combines clsx and tailwind-merge: import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
Shimmer class reference
The shimmer utility provides these classes: `shimmer` applies background-clip: text and animation: tw-shimmer var(--shimmer-duration, 2s) linear infinite; `shimmer-once` sets animation-iteration-count: 1; `shimmer-reverse` sets animation-direction: reverse; `shimmer-none` sets --shimmer-image: none and --shimmer-text-fill: currentColor; `shimmer-color-<color>` sets --shimmer-color: <color>; `shimmer-color-[<value>]` sets --shimmer-color: <value>; `shimmer-color-<color>/<pct>` sets --shimmer-color: color-mix(in oklch, <color> <pct>, transparent); `shimmer-duration-<number>` sets --shimmer-duration: calc(<number> * 1ms); `shimmer-spread-<number>` sets --shimmer-spread: calc(var(--spacing) * <number>); `shimmer-spread-[<value>]` sets --shimmer-spread: <value>; `shimmer-angle-<number>` sets --shimmer-angle: calc(<number> * 1deg);
Shimmer utility installation
The shimmer utility ships with the shadcn package. If your project was set up with `npx shadcn@latest init`, you already have shimmer. Otherwise, install the shadcn package with `npm install shadcn` and import shared utilities in your global CSS file with `@import "tailwindcss"; @import "shadcn/tailwind.css";`
Shimmer basic usage example
To add a shimmer effect to text, add the `shimmer` class to a text element: `<p className="shimmer text-muted-foreground">Generating response…</p>`
Shimmer uses currentColor for adaptation
The shimmer effect is built on currentColor, so it automatically adapts to the element's text color. The highlight is derived from the text color with no configuration needed, works on any color from text-muted-foreground to brand colors, and in dark mode the highlight automatically brightens to stay visible.
Shimmer with Marker component example
The shimmer utility composes with components that render text, such as the Marker component. Example: `<Marker role="status"><MarkerIcon><Spinner /></MarkerIcon><MarkerContent className="shimmer">Thinking…</MarkerContent></Marker>`
Shimmer color customization
Use `shimmer-color-<color>` to set the highlight color explicitly. It accepts theme colors with an optional opacity modifier (e.g., `shimmer-color-blue-500/60`) or arbitrary color values (e.g., `shimmer-color-[#378ADD]`).
Shimmer duration control
Use `shimmer-duration-<number>` to set the duration of one sweep in milliseconds. The default is 2000 (i.e., 2 seconds). Example: `<p className="shimmer shimmer-duration-1000">Generating response…</p>`
Shimmer spread (highlight width) control
Use `shimmer-spread-<number>` to set the width of the highlight band using the spacing scale. The default is `calc(3ch + 40px)`. For one-off values, use an arbitrary length or percentage with `shimmer-spread-[<value>]`. Example: `<p className="shimmer shimmer-spread-24">Generating response…</p>`
Shimmer angle control
Use `shimmer-angle-<number>` to set the tilt of the highlight band in degrees. The default is 20 degrees. Example: `<p className="shimmer shimmer-angle-45">Generating response…</p>`
Shimmer reverse direction
Use `shimmer-reverse` to sweep the highlight in the opposite direction. In RTL layouts the sweep already follows the reading direction. Example: `<p className="shimmer shimmer-reverse">Generating response…</p>`
Shimmer play once (single sweep)
Use `shimmer-once` to play a single sweep instead of looping. This is useful as a reveal when streaming completes. Pair it with `shimmer-duration-<number>` to control the sweep duration. Example: `<p className="shimmer shimmer-duration-1100 shimmer-once">Response generated.</p>`
Disabling shimmer with shimmer-none
Use `shimmer-none` to turn the shimmer effect off and render the text normally. It works in any class order, so it's useful for responsive or stateful styling. Example: `<p className="shimmer md:shimmer-none">Generating response…</p>`
Shimmer browser compatibility and fallback
The shimmer utility is built on modern CSS color features including relative color syntax and color-mix(), available in all current browsers. In older browsers without support, the highlight gradient is dropped and text may render transparent. If targeting older browsers, apply shimmer conditionally with a supports-* variant: `<p className="supports-[color:oklch(from_white_l_c_h)]:shimmer">Generating response…</p>`
Shimmer reduced motion support
When the user prefers reduced motion, the shimmer animation is automatically disabled and the text renders normally. There is nothing to configure.
Shimmer RTL (right-to-left) support
The shimmer sweep follows the reading direction: left to right in LTR and right to left in RTL, with no extra classes needed. To enable RTL support in shadcn/ui, see the RTL configuration guide. Use `shimmer-reverse` to flip the direction manually.
scroll-fade reveal distance example
Example of customizing the scroll-fade reveal distance: <div className="scroll-fade overflow-y-auto [--scroll-fade-reveal:64px]">{/* ... */}</div>
scroll-fade size example
Example of using scroll-fade with a specific fade size: <div className="scroll-fade overflow-y-auto scroll-fade-24">{/* ... */}</div>
scroll-fade responsive disabling example
Example of disabling scroll-fade responsively: <div className="scroll-fade overflow-y-auto md:scroll-fade-none">{/* ... */}</div>
scroll-fade arbitrary value example
Example of using scroll-fade with an arbitrary length value: <div className="scroll-fade overflow-y-auto scroll-fade-[15%]">{/* ... */}</div>
scroll-fade per-edge sizes example
Example of using scroll-fade with different sizes on opposite edges: <div className="scroll-fade overflow-y-auto scroll-fade-b-8 scroll-fade-t-2">{/* ... */}</div>
scroll-fade edge example
Example of using scroll-fade-b to apply fade only to the bottom edge: <div className="scroll-fade-b overflow-y-auto">{/* ... */}</div>
scroll-fade basic usage
Add scroll-fade or scroll-fade-y to the scroll container, the element that has overflow-y-auto. The fade is scroll-aware: at rest, the top edge is crisp and the bottom edge fades to hint at more content. As you scroll, a fade appears at the top and both edges stay faded mid-scroll. At the end, the bottom edge sharpens to show you have reached the last item.
scroll-fade classes and styles
scroll-fade and scroll-fade-y apply mask-image: var(--scroll-fade-mask, var(--scroll-fade-block)) and animation-timeline: scroll(self y). scroll-fade-x applies mask-image: var(--scroll-fade-mask, var(--scroll-fade-inline)) and animation-timeline: scroll(self inline). scroll-fade-t applies fade mask on the top edge with animation-timeline: scroll(self y). scroll-fade-b applies fade mask on the bottom edge with animation-timeline: scroll(self y). scroll-fade-l applies fade mask on the left edge with animation-timeline: scroll(self x). scroll-fade-r applies fade mask on the right edge with animation-timeline: scroll(self x). scroll-fade-s applies fade mask on the start edge (mirrors in RTL) with animation-timeline: scroll(self inline). scroll-fade-e applies fade mask on the end edge (mirrors in RTL) with animation-timeline: scroll(self inline). scroll-fade-<number> applies --scroll-fade-size: calc(var(--spacing) * <number>). scroll-fade-[<value>] applies --scroll-fade-size: <value>. scroll-fade-{t,b,s,e}-<number> applies --scroll-fade-{t,b,s,e}-size: calc(var(--spacing) * <number>). scroll-fade-{t,b,s,e}-[<value>] applies --scroll-fade-{t,b,s,e}-size: <value>. scroll-fade-none applies --scroll-fade-mask: none.
scroll-fade mask-image behavior
The fade is applied with mask-image, so it dissolves the content itself rather than overlaying a color. The mask uses a linear fade from transparent to black, so it adapts to any background without configuration. If your scroll area sits inside a card, put the background and border on a wrapper and scroll-fade on the inner scroller, so the fade dissolves the content and not the card.
scroll-fade with no overflow
If the content does not overflow, no fade is shown. You can apply scroll-fade to any list without checking whether it scrolls.
scroll-fade-x horizontal scrolling
Use scroll-fade-x on containers that scroll horizontally, the element that has overflow-x-auto. The horizontal fade is direction-aware. In RTL layouts, the crisp edge and the fade follow the reading direction with no extra classes needed.
scroll-fade edge utilities
Use scroll-fade-t, scroll-fade-b, scroll-fade-l, and scroll-fade-r for physical edges. Use scroll-fade-s and scroll-fade-e for logical inline edges that mirror in RTL. Edge utilities are scroll-aware: start edges fade in after you scroll away from the start, and end edges fade out when you reach the end.
scroll-fade size configuration
The fade depth defaults to 12% of the container, capped at 40px so tall scrollers stay subtle. Use scroll-fade-<number> to set a fixed size on the spacing scale the same way scroll-mt-<number> works. For one-off values, use an arbitrary length or percentage like scroll-fade-[15%]. To fade opposite edges by different amounts, use the per-edge modifiers scroll-fade-t-<number>, scroll-fade-b-<number>, scroll-fade-s-<number>, and scroll-fade-e-<number>. They override scroll-fade-<number> on the edge they target and accept arbitrary values too.
scroll-fade reveal distance variable
The fade eases in and out over a fixed scroll distance using the --scroll-fade-reveal variable, which defaults to 96px and is independent of the fade depth. You can lower it for a snappier reveal or raise it for a more gradual one by setting it inline like [--scroll-fade-reveal:64px].
scroll-fade-none disabling
Use scroll-fade-none to remove the fade. It works in any class order, so the typical use is responsive or stateful like md:scroll-fade-none.
scroll-fade fallback for unsupported browsers
The scroll-aware behavior is implemented with CSS scroll-driven animations, with no JavaScript and no scroll listeners. In browsers that do not support scroll-driven animations, scroll-fade falls back to a static fade on both edges, and edge utilities fall back to a static fade on the selected edge.
scroll-fade with scrollbar
Since the mask is applied to the scroll container itself, a visible scrollbar fades with the content at the edges. Pair scroll-fade with no-scrollbar, which ships in the same package, if you want to hide the scrollbar entirely.
scroll-fade RTL support
scroll-fade-x follows the reading direction. At rest, the start edge is crisp and the end edge fades. In RTL layouts that means a crisp right edge and a fade on the left, mirrored from LTR. To enable RTL support in shadcn/ui, see the RTL configuration guide.
scroll-fade horizontal example
Example of using scroll-fade-x for horizontal scrolling: <div className="flex scroll-fade-x overflow-x-auto">{/* ... */}</div>