- Components
- Layout
- Scroll area
Scroll area
Augments native scroll functionality for custom, cross-browser styling.
default.tsx
import * as React from "react";
import { ScrollArea } from "@/lib/components/core/default/scroll-area";
function Demo() {
return (
<div className="rounded-md border p-6">
<ScrollArea className="h-72 w-full max-w-sm" type="always">
<div className="space-y-4 p-4 pr-8">
<h4 className="text-md font-bold">Principles of the typographic craft</h4>
<p>
Three fundamental aspects of typography are legibility, readability, and aesthetics.
Although in a non-technical sense “legible” and “readable” are often used synonymously,
typographically they are separate but related concepts.
</p>
<p>
Legibility describes how easily individual characters can be distinguished from one
another. It is described by Walter Tracy as “the quality of being decipherable and
recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to
distinguish at small sizes, this is a problem of legibility.
</p>
<p>
Typographers are concerned with legibility insofar as it is their job to select the
correct font to use. Brush Script is an example of a font containing many characters
that might be difficult to distinguish. The selection of cases influences the legibility
of typography because using only uppercase letters (all-caps) reduces legibility.
</p>
</div>
</ScrollArea>
</div>
);
}
Installation
Copy and paste the following code into your project.
scroll-area.tsx
"use client";
import * as React from "react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import { type VariantProps, tv } from "tailwind-variants";
const scrollAreaStyles = tv({
slots: {
root: "flex flex-col h-full w-full overflow-hidden",
viewport: "h-full w-full flex flex-col [&>*]:!block [&>*]:w-fit [&>*]:grow",
scrollbar:
"flex touch-none select-none flex-col data-[orientation=horizontal]:flex-row data-[orientation=vertical]:flex-col bg-gray-800 rounded-full m-1",
thumb:
"relative before:absolute before:content-[''] before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2] w-full h-full before:min-w-4 before:min-h-4 bg-gray-500 hover:bg-gray-400 transition-colors rounded-[inherit]",
},
variants: {
size: {
sm: {
scrollbar: "data-[orientation=horizontal]:h-1 data-[orientation=vertical]:w-1",
},
md: {
scrollbar: "data-[orientation=horizontal]:h-2 data-[orientation=vertical]:w-2",
},
lg: {
scrollbar: "data-[orientation=horizontal]:h-3 data-[orientation=vertical]:w-3",
},
},
},
defaultVariants: {
size: "md",
},
});
interface ScrollAreaProps
extends ScrollAreaRootProps,
Omit<ScrollAreaViewPortProps, "dir">,
VariantProps<typeof scrollAreaStyles> {
scrollbars?: "vertical" | "horizontal" | "both";
}
const ScrollArea = ({
children,
scrollbars = "vertical",
size,
asChild,
type,
scrollHideDelay,
dir,
...viewportProps
}: ScrollAreaProps) => {
return (
<ScrollAreaRoot asChild={asChild} scrollHideDelay={scrollHideDelay} dir={dir} type={type}>
<ScrollAreaViewPort {...viewportProps}>{children}</ScrollAreaViewPort>
{scrollbars !== "vertical" && <ScrollAreaScrollbar orientation="horizontal" size={size} />}
{scrollbars !== "horizontal" && <ScrollAreaScrollbar orientation="vertical" size={size} />}
{scrollbars === "both" && <ScrollAreaCorner />}
</ScrollAreaRoot>
);
};
type ScrollAreaRootProps = ScrollAreaPrimitive.ScrollAreaProps;
const ScrollAreaRoot = ({ className, ...props }: ScrollAreaRootProps) => {
const { root } = scrollAreaStyles();
return <ScrollAreaPrimitive.Root className={root({ className })} {...props} />;
};
type ScrollAreaViewPortProps = ScrollAreaPrimitive.ScrollAreaViewportProps;
const ScrollAreaViewPort = ({ className, ...props }: ScrollAreaViewPortProps) => {
const { viewport } = scrollAreaStyles();
return <ScrollAreaPrimitive.Viewport className={viewport({ className })} {...props} />;
};
interface ScrollAreaScrollbarProps
extends ScrollAreaPrimitive.ScrollAreaScrollbarProps,
VariantProps<typeof scrollAreaStyles> {}
const ScrollAreaScrollbar = ({ className, size, ...props }: ScrollAreaScrollbarProps) => {
const { scrollbar, thumb } = scrollAreaStyles({ size });
return (
<ScrollAreaPrimitive.Scrollbar className={scrollbar({ className })} {...props}>
<ScrollAreaPrimitive.Thumb className={thumb()} />
</ScrollAreaPrimitive.Scrollbar>
);
};
const ScrollAreaCorner = ScrollAreaPrimitive.Corner;
export type {
ScrollAreaProps,
ScrollAreaRootProps,
ScrollAreaViewPortProps,
ScrollAreaScrollbarProps,
};
export { ScrollArea, ScrollAreaRoot, ScrollAreaViewPort, ScrollAreaScrollbar, ScrollAreaCorner };
Update the import paths to match your project setup.
Usage
Use ScrollArea to augment native scroll functionality for custom, cross-browser styling.
Options
Sizes
sizes.tsx
import * as React from "react";
import { ScrollArea } from "@/lib/components/core/default/scroll-area";
const sizes = ["sm", "md", "lg"] as const;
function Demo() {
return (
<div className="grid grid-cols-3 gap-10">
{sizes.map((size) => (
<div key={size} className="rounded-md border p-3">
<ScrollArea size={size} className="h-72" type="always">
<div className="space-y-4 p-4 pr-8">
<h4 className="text-md font-bold">Principles of the typographic craft</h4>
<p>
Three fundamental aspects of typography are legibility, readability, and aesthetics.
Although in a non-technical sense “legible” and “readable” are often used
synonymously, typographically they are separate but related concepts.
</p>
<p>
Legibility describes how easily individual characters can be distinguished from one
another. It is described by Walter Tracy as “the quality of being decipherable and
recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult
to distinguish at small sizes, this is a problem of legibility.
</p>
<p>
Typographers are concerned with legibility insofar as it is their job to select the
correct font to use. Brush Script is an example of a font containing many characters
that might be difficult to distinguish. The selection of cases influences the
legibility of typography because using only uppercase letters (all-caps) reduces
legibility.
</p>
</div>
</ScrollArea>
</div>
))}
</div>
);
}
Scrollbars
scrollbars.tsx
"use client";
import * as React from "react";
import { Radio, RadioGroup } from "@/lib/components/core/default/radio-group";
import { ScrollArea, type ScrollAreaProps } from "@/lib/components/core/default/scroll-area";
function Demo() {
const [scrollbars, setScrollbars] = React.useState("vertical");
return (
<div className="flex items-center gap-10">
<div className="rounded-md border p-6">
<ScrollArea
scrollbars={scrollbars as ScrollAreaProps["scrollbars"]}
className="h-44 w-full max-w-sm"
type="always"
>
<div className="flex w-[500px] items-start gap-4">
<div className="space-y-4 p-4 pr-8">
<h4 className="text-md font-bold">Principles of the typographic craft</h4>
<p>
Three fundamental aspects of typography are legibility, readability, and aesthetics.
Although in a non-technical sense “legible” and “readable” are often used
synonymously, typographically they are separate but related concepts.
</p>
<p>
Legibility describes how easily individual characters can be distinguished from one
another. It is described by Walter Tracy as “the quality of being decipherable and
recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult
to distinguish at small sizes, this is a problem of legibility.
</p>
<p>
Typographers are concerned with legibility insofar as it is their job to select the
correct font to use. Brush Script is an example of a font containing many characters
that might be difficult to distinguish. The selection of cases influences the
legibility of typography because using only uppercase letters (all-caps) reduces
legibility.
</p>
</div>
<div className="space-y-4 p-4 pr-8">
<h4 className="text-md font-bold">Principles of the typographic craft</h4>
<p>
Three fundamental aspects of typography are legibility, readability, and aesthetics.
Although in a non-technical sense “legible” and “readable” are often used
synonymously, typographically they are separate but related concepts.
</p>
<p>
Legibility describes how easily individual characters can be distinguished from one
another. It is described by Walter Tracy as “the quality of being decipherable and
recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult
to distinguish at small sizes, this is a problem of legibility.
</p>
<p>
Typographers are concerned with legibility insofar as it is their job to select the
correct font to use. Brush Script is an example of a font containing many characters
that might be difficult to distinguish. The selection of cases influences the
legibility of typography because using only uppercase letters (all-caps) reduces
legibility.
</p>
</div>
</div>
</ScrollArea>
</div>
<RadioGroup label="Scrollbars" value={scrollbars} onChange={setScrollbars}>
<Radio value="vertical">Vertical</Radio>
<Radio value="horizontal">Horizontal</Radio>
<Radio value="both">Both</Radio>
</RadioGroup>
</div>
);
}
API Reference
ScrollArea accepts all HTML div element props and the following:
Prop | Type | Default | Description |
---|---|---|---|
type | 'auto' | 'always' | 'scroll' | 'hover' | 'hover' | Describes the nature of scrollbar visibility. |
scrollHideDelay | number | 600 | If type is set to either 'scroll' or 'hover', this prop determines the length of time, in milliseconds, before the scrollbars are hidden after the user stops interacting with scrollbars. |
dir | 'ltr' | 'rtl' | 600 | The reading direction of the scroll area |
scrollbars | 'vertical' | 'horizontal' | 'both' | 'vertical' | Controls the scrollable axes. |