Layout
Scroll Area.
A scroll container with a thin custom scrollbar that turns orange on hover.
import * as React from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
const tags = Array.from({ length: 40 }, (_, i) => `v1.${40 - i}.0`);
export default function ScrollAreaDemo() {
return (
<ScrollArea className="h-72 w-48 rounded-lg border bg-card">
<div className="p-4">
<h4 className="mb-4 font-mono text-[10px] font-semibold tracking-[0.2em] text-success uppercase">Firmware tags</h4>
{tags.map((tag) => (
<React.Fragment key={tag}>
<div className="font-mono text-sm">{tag}</div>
<Separator className="my-2" />
</React.Fragment>
))}
</div>
</ScrollArea>
);
}Installation#
With the CLI
$npx lanterncn add scroll-areaThis also installs the Lantern theme and any Lantern UI components it depends on. The shadcn CLI works directly too: npx shadcn@latest add httptim/lantern-ui/scroll-area. See Installation if your project is not set up yet.
Manually
Install the dependencies
npm install radix-uiCopy the source into your project
components/ui/scroll-area.tsx"use client"; import * as React from "react"; import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"; import { cn } from "@/lib/utils"; function ScrollArea({ className, children, ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) { return ( <ScrollAreaPrimitive.Root data-slot="scroll-area" className={cn("relative", className)} {...props}> <ScrollAreaPrimitive.Viewport data-slot="scroll-area-viewport" className="size-full rounded-[inherit] transition-[box-shadow] outline-none focus-visible:ring-2 focus-visible:ring-ring/25" > {children} </ScrollAreaPrimitive.Viewport> <ScrollBar /> <ScrollAreaPrimitive.Corner /> </ScrollAreaPrimitive.Root> ); } function ScrollBar({ className, orientation = "vertical", ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) { return ( <ScrollAreaPrimitive.ScrollAreaScrollbar data-slot="scroll-area-scrollbar" orientation={orientation} className={cn( "group/scrollbar flex touch-none p-0.5 transition-colors select-none", orientation === "vertical" && "h-full w-2 border-l border-l-transparent", orientation === "horizontal" && "h-2 flex-col border-t border-t-transparent", className, )} {...props} > <ScrollAreaPrimitive.ScrollAreaThumb data-slot="scroll-area-thumb" className="relative flex-1 rounded-full bg-border transition-colors group-hover/scrollbar:bg-primary/80 active:bg-primary" /> </ScrollAreaPrimitive.ScrollAreaScrollbar> ); } export { ScrollArea, ScrollBar };Update the import paths to match your project
The source imports
cnfrom@/lib/utils.
Usage#
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";<ScrollArea className="h-72 w-48 rounded-lg border">
{items}
</ScrollArea>For sideways scrolling add <ScrollBar orientation="horizontal" /> inside the ScrollArea and give the content w-max.
Examples#
Horizontal
import { CpuIcon, HardDriveIcon, MonitorIcon, RadioTowerIcon, ServerIcon, TerminalSquareIcon } from "lucide-react";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
const hubs = [
{ name: "North hub", owner: "miner-02", icon: ServerIcon },
{ name: "Relay tower", owner: "computer 17", icon: RadioTowerIcon },
{ name: "Turtle yard", owner: "farmer-07", icon: CpuIcon },
{ name: "Archive", owner: "computer 58", icon: HardDriveIcon },
{ name: "Arcade", owner: "computer 9", icon: MonitorIcon },
{ name: "Shell club", owner: "computer 33", icon: TerminalSquareIcon },
];
export default function ScrollAreaHorizontal() {
return (
<ScrollArea className="w-full max-w-md rounded-lg border bg-card whitespace-nowrap">
<div className="flex w-max gap-4 p-4">
{hubs.map((hub) => (
<figure key={hub.name} className="w-40 shrink-0">
<div className="flex h-28 items-center justify-center rounded-md border bg-accent bg-grid text-[#b7ca9e]">
<hub.icon className="size-9 stroke-[1.25]" />
</div>
<figcaption className="mt-2">
<div className="font-display text-sm font-medium">{hub.name}</div>
<div className="font-mono text-[10px] tracking-[0.16em] text-muted-foreground uppercase">{hub.owner}</div>
</figcaption>
</figure>
))}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
);
}