Build websites 10x faster with HextaUI Blocks — Learn more
UI/UI

Scroll Area

A customizable scroll area component with smooth scrolling and accessible scrollbars.

Item 1: This is a scrollable item with some content
Item 2: This is a scrollable item with some content
Item 3: This is a scrollable item with some content
Item 4: This is a scrollable item with some content
Item 5: This is a scrollable item with some content
Item 6: This is a scrollable item with some content
Item 7: This is a scrollable item with some content
Item 8: This is a scrollable item with some content
Item 9: This is a scrollable item with some content
Item 10: This is a scrollable item with some content
Item 11: This is a scrollable item with some content
Item 12: This is a scrollable item with some content
Item 13: This is a scrollable item with some content
Item 14: This is a scrollable item with some content
Item 15: This is a scrollable item with some content
Item 16: This is a scrollable item with some content
Item 17: This is a scrollable item with some content
Item 18: This is a scrollable item with some content
Item 19: This is a scrollable item with some content
Item 20: This is a scrollable item with some content
Item 21: This is a scrollable item with some content
Item 22: This is a scrollable item with some content
Item 23: This is a scrollable item with some content
Item 24: This is a scrollable item with some content
Item 25: This is a scrollable item with some content
Item 26: This is a scrollable item with some content
Item 27: This is a scrollable item with some content
Item 28: This is a scrollable item with some content
Item 29: This is a scrollable item with some content
Item 30: This is a scrollable item with some content
Item 31: This is a scrollable item with some content
Item 32: This is a scrollable item with some content
Item 33: This is a scrollable item with some content
Item 34: This is a scrollable item with some content
Item 35: This is a scrollable item with some content
Item 36: This is a scrollable item with some content
Item 37: This is a scrollable item with some content
Item 38: This is a scrollable item with some content
Item 39: This is a scrollable item with some content
Item 40: This is a scrollable item with some content
Item 41: This is a scrollable item with some content
Item 42: This is a scrollable item with some content
Item 43: This is a scrollable item with some content
Item 44: This is a scrollable item with some content
Item 45: This is a scrollable item with some content
Item 46: This is a scrollable item with some content
Item 47: This is a scrollable item with some content
Item 48: This is a scrollable item with some content
Item 49: This is a scrollable item with some content
Item 50: This is a scrollable item with some content
<ScrollArea className="h-72 w-full rounded-md border border-[hsl(var(--hu-border))] p-4">
  <div className="space-y-4">
    {Array.from({ length: 50 }).map((_, i) => (
      <div
        key={i}
        className="text-sm text-[hsl(var(--hu-foreground))] p-2 rounded bg-[hsl(var(--hu-accent))]"
      >
        Item {i + 1}: This is a scrollable item with some content
      </div>
    ))}
  </div>
</ScrollArea>

Installation

Install following dependencies:

npm install @radix-ui/react-scroll-area class-variance-authority
pnpm add @radix-ui/react-scroll-area class-variance-authority
yarn add @radix-ui/react-scroll-area class-variance-authority
bun add @radix-ui/react-scroll-area class-variance-authority

Copy and paste the following code into your project.

components/ui/ScrollArea/scroll-area.tsx
"use client";

import * as React from "react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const scrollAreaVariants = cva("relative overflow-hidden", {
  variants: {
    orientation: {
      vertical: "h-full",
      horizontal: "w-full",
      both: "h-full w-full",
    },
  },
  defaultVariants: {
    orientation: "vertical",
  },
});

const scrollBarVariants = cva("flex touch-none select-none transition-colors", {
  variants: {
    orientation: {
      vertical: "h-full w-2.5 border-l border-l-transparent p-[1px]",
      horizontal: "h-2.5 w-full border-t border-t-transparent p-[1px]",
    },
  },
  defaultVariants: {
    orientation: "vertical",
  },
});

export interface ScrollAreaProps
  extends React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>,
    VariantProps<typeof scrollAreaVariants> {
  scrollHideDelay?: number;
  type?: "auto" | "always" | "scroll" | "hover";
}

const ScrollArea = React.forwardRef<
  React.ElementRef<typeof ScrollAreaPrimitive.Root>,
  ScrollAreaProps
>(
  (
    {
      className,
      children,
      orientation,
      scrollHideDelay = 600,
      type = "hover",
      ...props
    },
    ref,
  ) => (
    <ScrollAreaPrimitive.Root
      ref={ref}
      className={cn(scrollAreaVariants({ orientation }), className)}
      {...props}
    >
      <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
        {children}
      </ScrollAreaPrimitive.Viewport>
      <ScrollBar
        orientation="vertical"
        type={type}
        scrollHideDelay={scrollHideDelay}
      />
      {(orientation === "horizontal" || orientation === "both") && (
        <ScrollBar
          orientation="horizontal"
          type={type}
          scrollHideDelay={scrollHideDelay}
        />
      )}
      <ScrollAreaPrimitive.Corner />
    </ScrollAreaPrimitive.Root>
  ),
);

ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;

interface ScrollBarProps
  extends React.ComponentPropsWithoutRef<
    typeof ScrollAreaPrimitive.ScrollAreaScrollbar
  > {
  scrollHideDelay?: number;
  type?: "auto" | "always" | "scroll" | "hover";
}

const ScrollBar = React.forwardRef<
  React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
  ScrollBarProps
>(
  (
    { className, orientation = "vertical", scrollHideDelay, type, ...props },
    ref,
  ) => (
    <ScrollAreaPrimitive.ScrollAreaScrollbar
      ref={ref}
      orientation={orientation}
      className={cn(
        scrollBarVariants({ orientation }),
        "hover:bg-[hsl(var(--hu-accent))]",
        className,
      )}
      scrollHideDelay={scrollHideDelay}
      type={type}
      {...props}
    >
      <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-[hsl(var(--hu-border))] hover:bg-[hsl(var(--hu-foreground))]/30 transition-colors" />
    </ScrollAreaPrimitive.ScrollAreaScrollbar>
  ),
);

ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;

export { ScrollArea, ScrollBar, scrollAreaVariants };
npx hextaui@latest add scroll-area
pnpm dlx hextaui@latest add scroll-area
yarn dlx hextaui@latest add scroll-area
bun x hextaui@latest add scroll-area

Usage

import { ScrollArea } from "@/components/ui/ScrollArea";
<ScrollArea className="h-72 w-full rounded-md border">
  <div className="p-4">{/* Your scrollable content */}</div>
</ScrollArea>

Examples

Default

Item 1: This is a scrollable item with some content
Item 2: This is a scrollable item with some content
Item 3: This is a scrollable item with some content
Item 4: This is a scrollable item with some content
Item 5: This is a scrollable item with some content
Item 6: This is a scrollable item with some content
Item 7: This is a scrollable item with some content
Item 8: This is a scrollable item with some content
Item 9: This is a scrollable item with some content
Item 10: This is a scrollable item with some content
Item 11: This is a scrollable item with some content
Item 12: This is a scrollable item with some content
Item 13: This is a scrollable item with some content
Item 14: This is a scrollable item with some content
Item 15: This is a scrollable item with some content
Item 16: This is a scrollable item with some content
Item 17: This is a scrollable item with some content
Item 18: This is a scrollable item with some content
Item 19: This is a scrollable item with some content
Item 20: This is a scrollable item with some content
Item 21: This is a scrollable item with some content
Item 22: This is a scrollable item with some content
Item 23: This is a scrollable item with some content
Item 24: This is a scrollable item with some content
Item 25: This is a scrollable item with some content
Item 26: This is a scrollable item with some content
Item 27: This is a scrollable item with some content
Item 28: This is a scrollable item with some content
Item 29: This is a scrollable item with some content
Item 30: This is a scrollable item with some content
Item 31: This is a scrollable item with some content
Item 32: This is a scrollable item with some content
Item 33: This is a scrollable item with some content
Item 34: This is a scrollable item with some content
Item 35: This is a scrollable item with some content
Item 36: This is a scrollable item with some content
Item 37: This is a scrollable item with some content
Item 38: This is a scrollable item with some content
Item 39: This is a scrollable item with some content
Item 40: This is a scrollable item with some content
Item 41: This is a scrollable item with some content
Item 42: This is a scrollable item with some content
Item 43: This is a scrollable item with some content
Item 44: This is a scrollable item with some content
Item 45: This is a scrollable item with some content
Item 46: This is a scrollable item with some content
Item 47: This is a scrollable item with some content
Item 48: This is a scrollable item with some content
Item 49: This is a scrollable item with some content
Item 50: This is a scrollable item with some content
<ScrollArea className="h-72 w-full rounded-md border border-[hsl(var(--hu-border))] p-4">
  <div className="space-y-4">
    {Array.from({ length: 50 }).map((_, i) => (
      <div
        key={i}
        className="text-sm text-[hsl(var(--hu-foreground))] p-2 rounded bg-[hsl(var(--hu-accent))]"
      >
        Item {i + 1}: This is a scrollable item with some content
      </div>
    ))}
  </div>
</ScrollArea>

Vertical Scrolling (Default)

Tags

A list of tags in vertical scroll area

v1.2.0-beta.50
v1.2.0-beta.49
v1.2.0-beta.48
v1.2.0-beta.47
v1.2.0-beta.46
v1.2.0-beta.45
v1.2.0-beta.44
v1.2.0-beta.43
v1.2.0-beta.42
v1.2.0-beta.41
v1.2.0-beta.40
v1.2.0-beta.39
v1.2.0-beta.38
v1.2.0-beta.37
v1.2.0-beta.36
v1.2.0-beta.35
v1.2.0-beta.34
v1.2.0-beta.33
v1.2.0-beta.32
v1.2.0-beta.31
v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
<ScrollArea
  orientation="vertical"
  className="h-72 w-full rounded-md border border-[hsl(var(--hu-border))] p-4"
>
  <div className="space-y-4">
    {Array.from({ length: 30 }).map((_, i) => (
      <div
        key={i}
        className="text-sm text-[hsl(var(--hu-foreground))] p-2 rounded bg-[hsl(var(--hu-accent))]"
      >
        Item {i + 1}: This is a scrollable item with some content
      </div>
    ))}
  </div>
</ScrollArea>

Horizontal Scrolling

Artwork Collection

A horizontal scrolling gallery of famous artworks

The Starry Night
Vincent van Gogh
Mona Lisa
Leonardo da Vinci
Guernica
Pablo Picasso
The Persistence of Memory
Salvador Dalí
Water Lilies
Claude Monet
The Scream
Edvard Munch
Girl with a Pearl Earring
Johannes Vermeer
The Creation of Adam
Michelangelo
No. 1, 1950
Jackson Pollock
American Gothic
Grant Wood
<ScrollArea
  orientation="horizontal"
  className="w-full rounded-md border border-[hsl(var(--hu-border))]"
>
  <div className="flex space-x-4 p-4">
    {Array.from({ length: 20 }).map((_, i) => (
      <div
        key={i}
        className="flex-shrink-0 w-32 h-24 p-2 rounded bg-[hsl(var(--hu-accent))] text-sm"
      >
        Card {i + 1}
      </div>
    ))}
  </div>
</ScrollArea>

Both Directions

Data Table

A table with both vertical and horizontal scrolling

NameEmailRoleDepartmentStatusActions
User 1user1@example.comAdminEngineeringActive
User 2user2@example.comViewerSalesInactive
User 3user3@example.comEditorMarketingActive
User 4user4@example.comAdminDesignInactive
User 5user5@example.comEditorEngineeringActive
User 6user6@example.comViewerSalesInactive
User 7user7@example.comAdminDesignActive
User 8user8@example.comViewerSalesInactive
User 9user9@example.comEditorEngineeringActive
User 10user10@example.comAdminDesignInactive
User 11user11@example.comEditorMarketingActive
User 12user12@example.comViewerSalesInactive
User 13user13@example.comAdminEngineeringActive
User 14user14@example.comViewerSalesInactive
User 15user15@example.comEditorMarketingActive
User 16user16@example.comAdminDesignInactive
User 17user17@example.comEditorEngineeringActive
User 18user18@example.comViewerSalesInactive
User 19user19@example.comAdminDesignActive
User 20user20@example.comViewerSalesInactive
User 21user21@example.comEditorEngineeringActive
User 22user22@example.comAdminDesignInactive
User 23user23@example.comEditorMarketingActive
User 24user24@example.comViewerSalesInactive
User 25user25@example.comAdminEngineeringActive
User 26user26@example.comViewerSalesInactive
User 27user27@example.comEditorMarketingActive
User 28user28@example.comAdminDesignInactive
User 29user29@example.comEditorEngineeringActive
User 30user30@example.comViewerSalesInactive
User 31user31@example.comAdminDesignActive
User 32user32@example.comViewerSalesInactive
User 33user33@example.comEditorEngineeringActive
User 34user34@example.comAdminDesignInactive
User 35user35@example.comEditorMarketingActive
User 36user36@example.comViewerSalesInactive
User 37user37@example.comAdminEngineeringActive
User 38user38@example.comViewerSalesInactive
User 39user39@example.comEditorMarketingActive
User 40user40@example.comAdminDesignInactive
User 41user41@example.comEditorEngineeringActive
User 42user42@example.comViewerSalesInactive
User 43user43@example.comAdminDesignActive
User 44user44@example.comViewerSalesInactive
User 45user45@example.comEditorEngineeringActive
User 46user46@example.comAdminDesignInactive
User 47user47@example.comEditorMarketingActive
User 48user48@example.comViewerSalesInactive
User 49user49@example.comAdminEngineeringActive
User 50user50@example.comViewerSalesInactive
User 51user51@example.comEditorMarketingActive
User 52user52@example.comAdminDesignInactive
User 53user53@example.comEditorEngineeringActive
User 54user54@example.comViewerSalesInactive
User 55user55@example.comAdminDesignActive
User 56user56@example.comViewerSalesInactive
User 57user57@example.comEditorEngineeringActive
User 58user58@example.comAdminDesignInactive
User 59user59@example.comEditorMarketingActive
User 60user60@example.comViewerSalesInactive
User 61user61@example.comAdminEngineeringActive
User 62user62@example.comViewerSalesInactive
User 63user63@example.comEditorMarketingActive
User 64user64@example.comAdminDesignInactive
User 65user65@example.comEditorEngineeringActive
User 66user66@example.comViewerSalesInactive
User 67user67@example.comAdminDesignActive
User 68user68@example.comViewerSalesInactive
User 69user69@example.comEditorEngineeringActive
User 70user70@example.comAdminDesignInactive
User 71user71@example.comEditorMarketingActive
User 72user72@example.comViewerSalesInactive
User 73user73@example.comAdminEngineeringActive
User 74user74@example.comViewerSalesInactive
User 75user75@example.comEditorMarketingActive
User 76user76@example.comAdminDesignInactive
User 77user77@example.comEditorEngineeringActive
User 78user78@example.comViewerSalesInactive
User 79user79@example.comAdminDesignActive
User 80user80@example.comViewerSalesInactive
User 81user81@example.comEditorEngineeringActive
User 82user82@example.comAdminDesignInactive
User 83user83@example.comEditorMarketingActive
User 84user84@example.comViewerSalesInactive
User 85user85@example.comAdminEngineeringActive
User 86user86@example.comViewerSalesInactive
User 87user87@example.comEditorMarketingActive
User 88user88@example.comAdminDesignInactive
User 89user89@example.comEditorEngineeringActive
User 90user90@example.comViewerSalesInactive
User 91user91@example.comAdminDesignActive
User 92user92@example.comViewerSalesInactive
User 93user93@example.comEditorEngineeringActive
User 94user94@example.comAdminDesignInactive
User 95user95@example.comEditorMarketingActive
User 96user96@example.comViewerSalesInactive
User 97user97@example.comAdminEngineeringActive
User 98user98@example.comViewerSalesInactive
User 99user99@example.comEditorMarketingActive
User 100user100@example.comAdminDesignInactive
<ScrollArea
  orientation="both"
  className="h-72 w-full rounded-md border border-[hsl(var(--hu-border))]"
>
  <div className="p-4" style={{ width: "800px", height: "600px" }}>
    <div className="grid grid-cols-8 gap-4">
      {Array.from({ length: 64 }).map((_, i) => (
        <div
          key={i}
          className="w-20 h-20 p-2 rounded bg-[hsl(var(--hu-accent))] text-xs flex items-center justify-center"
        >
          {i + 1}
        </div>
      ))}
    </div>
  </div>
</ScrollArea>

Always Visible Scrollbar

Always Visible

Scrollbar is always visible

Always visible item 1
Always visible item 2
Always visible item 3
Always visible item 4
Always visible item 5
Always visible item 6
Always visible item 7
Always visible item 8
Always visible item 9
Always visible item 10
Always visible item 11
Always visible item 12
Always visible item 13
Always visible item 14
Always visible item 15
Always visible item 16
Always visible item 17
Always visible item 18
Always visible item 19
Always visible item 20
<ScrollArea type="always" className="h-48 w-full rounded-md border">
  <div className="p-4">
    {/* Content that requires scrolling */}
    {Array.from({ length: 20 }).map((_, i) => (
      <div key={i} className="p-2 mb-2 bg-accent rounded">
        Always visible item {i + 1}
      </div>
    ))}
  </div>
</ScrollArea>

Auto Hide Scrollbar

Auto Hide

Scrollbar appears only when needed

Auto hide item 1 (No scrollbar needed)
Auto hide item 2 (No scrollbar needed)
Auto hide item 3 (No scrollbar needed)
Auto hide item 4 (No scrollbar needed)
Auto hide item 5 (No scrollbar needed)
<ScrollArea type="auto" className="h-48 w-full rounded-md border">
  <div className="p-4">
    {/* Content that may or may not need scrolling */}
    {Array.from({ length: 5 }).map((_, i) => (
      <div key={i} className="p-2 mb-2 bg-accent rounded">
        Auto hide item {i + 1}
      </div>
    ))}
  </div>
</ScrollArea>

On Scroll Scrollbar

On Scroll

Scrollbar appears when scrolling

On scroll item 1
On scroll item 2
On scroll item 3
On scroll item 4
On scroll item 5
On scroll item 6
On scroll item 7
On scroll item 8
On scroll item 9
On scroll item 10
On scroll item 11
On scroll item 12
On scroll item 13
On scroll item 14
On scroll item 15
On scroll item 16
On scroll item 17
On scroll item 18
On scroll item 19
On scroll item 20
<ScrollArea type="scroll" className="h-48 w-full rounded-md border">
  <div className="p-4">
    {/* Scrollbar appears when scrolling */}
    {Array.from({ length: 20 }).map((_, i) => (
      <div key={i} className="p-2 mb-2 bg-accent rounded">
        On scroll item {i + 1}
      </div>
    ))}
  </div>
</ScrollArea>

On Hover Scrollbar (Default)

On Hover (Default)

Scrollbar appears on hover

On hover item 1
On hover item 2
On hover item 3
On hover item 4
On hover item 5
On hover item 6
On hover item 7
On hover item 8
On hover item 9
On hover item 10
On hover item 11
On hover item 12
On hover item 13
On hover item 14
On hover item 15
On hover item 16
On hover item 17
On hover item 18
On hover item 19
On hover item 20
<ScrollArea type="hover" className="h-48 w-full rounded-md border">
  <div className="p-4">
    {/* Scrollbar appears on hover (default behavior) */}
    {Array.from({ length: 20 }).map((_, i) => (
      <div key={i} className="p-2 mb-2 bg-accent rounded">
        On hover item {i + 1}
      </div>
    ))}
  </div>
</ScrollArea>

Props

PropTypeDefault
children?
React.ReactNode
undefined
className?
string
undefined
scrollHideDelay?
number
600
type?
"auto" | "always" | "scroll" | "hover"
"hover"
orientation?
"vertical" | "horizontal" | "both"
"vertical"
Edit on GitHub

Last updated on