Primitives
Scroll area
Scroll container with overlay scrollbars and edge fades.
Composition
The preferred shape for composing the installed primitive from its exported parts.
Root
Single-slot surface with no nested parts.
ScrollAreaThe refined source installs this primitive from src/registry/sources/refined/ui/scroll-area.tsx. Install it on its own with the command above, or inspect the source below.
npx shadcn@latest add http://127.0.0.1:3000/r/refined/scroll-area.jsonRaw code
Primary installed primitive source
Base UI Scroll area slot
src/registry/sources/refined/ui/scroll-area.tsx
"use client";import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";import type { CSSProperties } from "react";import type { ScrollAreaProps } from "@/components/refined-ui/contracts";import { cn } from "@/components/refined-ui/lib/cn";import { skinSlot } from "@/components/refined-ui/skin";// Edge fade driven by Base UI overflow flags — fades only sides that actually clip content.const maskBaseClasses = cn( "[mask-image:linear-gradient(to_right,var(--scroll-mask-x-start,#000),#000_var(--scroll-fade-size),#000_calc(100%_-_var(--scroll-fade-size)),var(--scroll-mask-x-end,#000)),linear-gradient(to_bottom,var(--scroll-mask-y-start,#000),#000_var(--scroll-fade-size),#000_calc(100%_-_var(--scroll-fade-size)),var(--scroll-mask-y-end,#000))]", "[mask-composite:intersect] [-webkit-mask-composite:source-in]",);const maskXOverflowClasses = cn( "data-[overflow-x-start]:[--scroll-mask-x-start:transparent]", "data-[overflow-x-end]:[--scroll-mask-x-end:transparent]",);const maskYOverflowClasses = cn( "data-[overflow-y-start]:[--scroll-mask-y-start:transparent]", "data-[overflow-y-end]:[--scroll-mask-y-end:transparent]",);const scrollbarVisibilityClasses = { always: "opacity-100", hover: "opacity-0 transition-opacity duration-[var(--duration-fast)] data-[hovering]:opacity-100 data-[scrolling]:opacity-100", scroll: "opacity-0 transition-opacity duration-[var(--duration-fast)] data-[scrolling]:opacity-100",};function Scrollbar({ orientation, visibility,}: { orientation: "vertical" | "horizontal"; visibility: ScrollAreaProps["scrollbarVisibility"];}) { return ( <ScrollAreaPrimitive.Scrollbar orientation={orientation} data-ui="agent" data-slot="scroll-area-scrollbar" className={cn( "m-px flex touch-none select-none", orientation === "vertical" ? "w-1.5 justify-center" : "h-1.5 flex-col", scrollbarVisibilityClasses[visibility ?? "scroll"], skinSlot("scroll-area-scrollbar", { orientation }), )} > <ScrollAreaPrimitive.Thumb data-ui="agent" data-slot="scroll-area-thumb" className={cn( "flex-1 rounded-full bg-foreground/25 transition-colors hover:bg-foreground/40", orientation === "vertical" ? "w-full" : "h-full", skinSlot("scroll-area-thumb", {}), )} /> </ScrollAreaPrimitive.Scrollbar> );}export function ScrollArea({ className, viewportClassName, maxHeight, mask = true, lockAxis, scrollbarVisibility = "scroll", children, ...props}: ScrollAreaProps) { const lockX = lockAxis === "x" || lockAxis === "both"; const lockY = lockAxis === "y" || lockAxis === "both"; const viewportStyle: CSSProperties | undefined = maxHeight || lockX || lockY ? { ...(maxHeight ? { maxHeight } : {}), ...(lockX ? { overflowX: "hidden" } : {}), ...(lockY ? { overflowY: "hidden" } : {}), } : undefined; return ( <ScrollAreaPrimitive.Root data-ui="agent" data-slot="scroll-area" className={cn("relative overflow-hidden", skinSlot("scroll-area", {}), className)} {...props} > {/* Overscroll left at default (chaining) so wheel falls through to parent when viewport can't scroll further; `overscroll-contain` would trap it. */} <ScrollAreaPrimitive.Viewport className={cn( "h-full w-full rounded-[inherit] outline-none", mask && maskBaseClasses, mask && !lockX && maskXOverflowClasses, mask && !lockY && maskYOverflowClasses, viewportClassName, )} style={viewportStyle} > <ScrollAreaPrimitive.Content style={{ minWidth: 0 }}>{children}</ScrollAreaPrimitive.Content> </ScrollAreaPrimitive.Viewport> {!lockY && <Scrollbar orientation="vertical" visibility={scrollbarVisibility} />} {!lockX && <Scrollbar orientation="horizontal" visibility={scrollbarVisibility} />} {!lockX && !lockY && ( <ScrollAreaPrimitive.Corner data-ui="agent" data-slot="scroll-area-corner" className={cn("bg-transparent", skinSlot("scroll-area-corner", {}))} /> )} </ScrollAreaPrimitive.Root> );}